Подтвердить что ты не робот

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

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

Я новичок в мире Haskell, перейдя из Lisp. Я пытаюсь приспособиться к принципиально другому мировоззрению Haskell, и одна из многих вещей, которые я нахожу новыми и захватывающими, - это система типов. Будучи Lisper, я думал, что попытаюсь реализовать в Haskell функцию, которая очень важна в мире Lisp: 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-х элементов, тип apply должен быть: (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 смысл в статически типизированном мировоззрении Haskell?

4b9b3361

Ответ 1

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

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

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


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

Ответ 2

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

Ответ 3

... функция, которая очень важна в мире Lisp: применить. Для тех кто не знает, 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]

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