Вызвать функцию Haskell с разнородными аргументами? - PullRequest
2 голосов
/ 13 марта 2010

В настоящее время я работаю над проектом на Haskell, который автоматически тестирует некоторые функции на основе спецификации XML. Спецификация XML дает аргументы для каждой функции и ожидаемый результат, который будет предоставлять функция (аргументы бывают разных типов). Я знаю, как извлечь аргументы функции из XML и проанализировать их, используя функцию чтения, но я не выяснил, как вызвать функцию, используя аргументы, которые я получаю.

То, что я в основном хочу, это прочитать и сохранить аргументы в гетерогенном списке (мое текущее мышление - использовать список типа Data.Dynamic), а затем вызвать функцию, передав этот гетерогенный список в качестве списка аргументов. Это возможно? Изменение тестируемых функций не вариант.

Ответы [ 2 ]

2 голосов
/ 13 марта 2010

Я бы порекомендовал Натану использовать Haskell в качестве языка спецификаций. Сам Haskell является наилучшим форматом данных для работы с функциями Haskell: -)

Но так как это интересный вопрос, я сделаю вид, что по каким-то странным причинам вам придется использовать XML. Вам нужно будет конвертировать ваш XML в настоящую функцию на Haskell. Это означает наличие некоторого отображения:

lookupFunc :: String -> ???

Который ищет функцию по имени. Вам нужно будет написать это отображение вручную или сгенерировать его с помощью Template Haskell. Но важно отметить, что ??? не является типом, и эта функция нуждается в реальном типе.

Вот аккуратный пример, похожий на ваш разнородный список, но более оптимизированный для рассматриваемой проблемы:

data SpecFunc = Result String | More (String -> SpecFunc)

Это ваш интерфейс к спецификации XML. Он говорит, что либо я закончил и уже получил результат (который уже был зачеркнут), либо мне нужен другой аргумент для продолжения (с преобразованием строки, запеченной в эту функцию). (Замечание стороны Geeky: это называется «свободная монада над (String ->)», но монадность сейчас для нас совершенно неактуальна).

Теперь мы можем написать класс типов для преобразования функций Haskell в их SpecFuncs, если их типы соответствуют нашим критериям:

class HasSpecFunc a where
    toSpecFunc :: a -> SpecFunc

instance (Read a, HasSpecFunc b) => HasSpecFunc (a -> b) where
    toSpecFunc f = More (\input -> toSpecFunc (f (read input)))

... -- one of these for each one of your "primitive" result types
instance HasSpecFunc String where
    toSpecFunc x = Result (show x)

Используя какое-то зло, вы можете избежать указания одного экземпляра для каждого типа результата. В верхней части файла включите перекрывающиеся экземпляры:

{-# LANGUAGE OverlappingInstances #-}

Тогда используйте:

instance (Show a) => HasSpecFunc a where
    toSpecFunc x = Result (show x)

Затем вы можете вызвать SpecFunc с чем-то вроде:

-- returns Nothing if the wrong number of arguments were provided
runSpecFunc :: SpecFunc -> [String] -> Maybe String
runSpecFunc (Result x) [] = Just x
runSpecFunc (More f) (x:xs) = runSpecFunc (f x) xs
runSpecFunc _ _ = Nothing

Надеюсь, это имело смысл. Но опять же, отказ от XML и использование вместо этого Haskell гораздо предпочтительнее.

0 голосов
/ 13 марта 2010

Использование Data.Dynamic, как правило, плохая идея, поскольку вы жертвуете способностью GHC проверять аргументы за вас. Почти всегда вы знаете действительные функции, которые должны поддерживать типы, поэтому вы можете всегда использовать экзистенциально типизированный список.

Вместо этого возможно ли создать тип данных, представляющий допустимые типы, которые будет генерировать ваш XML? То есть создайте ADT, который представляет абстрактный синтаксис правильно сформированных аргументов XML.

Например, посмотрите на JSON ADT: http://hackage.haskell.org/packages/archive/json/0.4.3/doc/html/src/Text-JSON-Types.html#JSValue

В качестве альтернативы используйте экзистенциальный тип, чтобы (статически) убедиться, что значения поддерживают методы, которые вы объявляете для них. Например, все значения в вашем XML должны поддерживать Show, возможно, чтобы вы могли описать гетерогенный список как:

data XMLList = forall a. Показать a => XMLList [a])

Пример из викибука Haskell: http://en.wikibooks.org/wiki/Haskell/Existentially_quantified_types#Example:_heterogeneous_lists

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...