Вопрос по haskell, lisp, types, polyvariadic – Haskell «Применить»? [Дубликат]

20

Possible Duplicate:
Why is such a function definition not allowed in 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

И я думаю, что понимаю почему. Тип приложения должен отличаться в зависимости от длины списка, который ему дан. Учитывая список, скажем, 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   ответа
2

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

Ну да но потомapply3 f (a:b:c:_) = f a b c это один лайнер.
Да, для определенных типов функций, я думаю. Но если у вас была такая функция, какdiscriminant a b c = b*b - 4*a*cв Лиспе ты сможешь сказать(apply discriminant '(2 3 4)), Вы не можете сделать это со сгибом. Ord
@DonStewart Круто! Я никогда не слышал оuncurry до. Но да, я понимаю, почему это на самом деле не распространенная идиома Хаскелла. Ord
С другой стороны, я не знаю, почему применение когда-либо будет использоваться таким образом. В Лиспе вы обычно используете apply, когда у вас есть функция, которая принимает любое количество аргументов, и эта концепция не переносится на Haskell. Ord
Вы можете играть в игры с карри, чтобы отразить арность во вложенных кортежах,uncurry ( uncurry discriminant ) ((2,3),4) ==> -23 , Это просто не то, что нужно делать на Хаскеле.
0

... a function which is very important in the Lisp world: apply. For those who don't know, apply takes a function and a list of arguments, and invokes the function on those arguments. In Scheme, (apply + '(1 2 3)) is the same as invoking (+ 1 2 3), and returns 6. ...

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

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

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

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

map f list

например

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

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

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

Не совсем. Если вы определитеdiscriminant a b c = b*b - 4*a*cв Лиспе ты сможешь сказать(apply discriminant '(2 3 4)), Другой (более полезный) пример: в Лиспе функция map может принимать любое количество аргументов списка. Не только могу сказать(map square '(1 2 3 4)) -> '(1 4 9 16)но могу сказать(map + '(1 2 3) '(4 5 6)) -> '(5 7 9) (который похож на zipWith), или(map * '(1 2 3) '(3 2 1) '(0 2 0)) -> '(0 8 0), Если у меня есть список списков, я смогу сказать(apply map + x) получить срочную сумму списков. Вы не можете делать ни одной из этих вещей со сгибом. Ord
11

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

asking for a general-purpose apply basically like asking for a function that can manipulate an arbitrary-length tuple?

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

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

Спасибо! На самом деле, я использую GHC на моем & quot; основном & quot; компьютер. Я набираю это где-то еще, поэтому я просто использовал codepad.org для проверки своих фрагментов кода. Я думаю, они используют объятия? Ord
@ Иногда они обнимаются, с-98 флаг. Увидетьcodepad.org/about

Похожие вопросы