Haskell "Применить"?

Возможный дубликат:
Почему такое определение функции не разрешено в haskell?

Я новичок в мире Haskell, перебираюсь из Lisp. Я пытаюсь приспособиться к принципиально другому мировоззрению Хаскелла, и одна из многих вещей, которые я нахожу новым и захватывающим, - это система типов. Будучи Лиспером, я подумал, что попытаюсь реализовать в Haskell функцию, которая очень важна в мире Лисп: apply, Для тех, кто не знает, apply принимает функцию и список аргументов и вызывает функцию для этих аргументов. На схеме (apply + '(1 2 3)) так же, как вызов (+ 1 2 3)и возвращает 6.

Мой код на Haskell выглядит примерно так:

apply x [] = x
apply f (x:xs) = apply (f x) xs

Но Хаскелл жалуется:

ERROR line 2 - Type error in function binding
*** Term           : apply
*** Type           : (b -> a) -> [b] -> a
*** Does not match : a -> [b] -> a
*** Because        : unification would give infinite type

И я думаю, что понимаю почему. Тип Apply должен отличаться в зависимости от длины списка, который ему дан. Учитывая список, скажем, 3 пунктов, тип применения должен быть: (a -> a -> a -> b) -> [a] -> b, но учитывая список из 6 элементов, тип применения должен быть: (a -> a -> a -> a -> a -> a -> b) -> [a] -> b,

Я попробовал этот ужасный обходной путь:

data FnOrDat a b = Dat b | Fn (a -> FnOrDat a b)

apply :: (FnOrDat a b) -> [a] -> (FnOrDat a b)
apply x [] = x
apply (Fn f) (x:xs) = apply (f x) xs
apply (Dat _) _ = error "Cannot apply something which is not a function!"

add a = Fn (\b -> Dat (a + b))

main = putStrLn $ show $ x where Dat x = apply (Fn add) [5,1]

Это работает, но вряд ли считается apply функция, потому что я не могу пройти apply нормальная функция, я должен использовать ту, которая была написана специально для использования моей (неудобной) абстракции FnOrDat. Если бы я хотел написать функцию, которая добавила четыре числа, мне нужно было бы написать

add4 a = Fn (\b -> Fn (\c -> Fn (\d -> Dat (a + b + c + d))))

Еа.

Итак - я что-то упускаю или прошу общего назначения apply в основном, как запросить функцию, которая может манипулировать кортежом произвольной длины? Есть ли apply даже имеет смысл в статически типизированном мировоззрении Хаскелла?

3 ответа

Решение

apply не очень полезен в Haskell, так как вы не можете дать тип функции. Как вы видите в своем FnOrDat, вы по сути встраиваете язык Lisp в Haskell как EDSL, чтобы что-то форсировать.

спрашивать о применении общего назначения в основном как запрос о функции, которая может манипулировать кортежом произвольной длины?

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


В качестве примечания следует рассмотреть возможность обновления до GHC и платформы Haskell вместо устаревшей системы Хугса, поскольку вы упускаете большинство библиотек, инструментов и языковых функций, разработанных за последние 10 лет.

Несмотря на объяснения Дона, foldl1 (+) фактически добавит все элементы списка. Следовательно, можно сказать, что fold Семейство функций довольно близко подходит к apply как ОП описывает это.

... функция, которая очень важна в мире Lisp: применить. Для тех, кто не знает, apply принимает функцию и список аргументов и вызывает функцию для этих аргументов. На схеме (apply + '(1 2 3)) то же самое, что вызов (+ 1 2 3) и возвращает 6....

Это довольно просто:

foldr  (+) 0 [1,2,3]
foldr1 (+)   [1,2,3]

результаты в 6.

Чтобы применить функцию к каждому элементу списка:

map f list

например

map (2*) [1,2,3]

результаты в [2,4,6]

Это то, что вы ищите?

Другие вопросы по тегам