Так что это не та же самая концепция, но это много тех композиционных вариантов использования, и добавляет еще несколько.

это определение не должно быть разрешено в ленивом языке, таком как Haskell, в котором функции каррируются?

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

Это в основном функция, которая применяет данную функцию к заданному списку аргументов, и это очень легко сделать, например, в Лиспе. Есть ли обходные пути?

 C. A. McCann29 мая 2011 г., 18:56
На самом деле это мой любимый пример потенциально полезной функции, которую невероятно больно писать на языке без динамических и зависимых типов. К счастью, это не так часто встречается на практике, потому что большинство реальных применений могут быть написаны по-разному.
 Thomas Eding26 сент. 2011 г., 22:19
Конечно, вы можете увидеть, если используетеf :: [a] -> b работает для вас. Тогда вам не нужноapply, Вызов версии с одним аргументом работает какf [x].
 KA120 июл. 2011 г., 12:58
просто хочу сказать, что это может быть один хороший пример того, почему мыЛЮБОВЬ статическая типизация.
 augustss29 мая 2011 г., 18:43
Один из способов понять, почему он не работает, - попытаться записать сигнатуру типа дляapply.
 Thomas M. DuBuisson29 мая 2011 г., 19:43
С участиемunsafeCoerce, все возможно ... даже лечение целых чисел и указателей и наоборот ...

Ответы на вопрос(3)

IncoherentInstances, используемый в этом случае, чтобы сделать частичное применение возможным - может быть немного сложным. Вот решение, которое не требует каких-либо расширений.

Сначала мы определяем тип данных функций, которые знают, что делать с любым количеством аргументов. Вы должны прочитатьa здесь как «тип аргумента», иb как «тип возвращаемого значения».

data ListF a b = Cons b (ListF a (a -> b))

Затем мы можем написать некоторые (Haskell) функции, которые изменяют эти (variadic) функции. Я используюF суффикс для любых функций, которые находятся в Prelude.

headF :: ListF a b -> b
headF (Cons b _) = b

mapF :: (b -> c) -> ListF a b -> ListF a c
mapF f (Cons v fs) = Cons (f v) (mapF (f.) fs)

partialApply :: ListF a b -> [a] -> ListF a b
partialApply fs          []     = fs
partialApply (Cons f fs) (x:xs) = partialApply (mapF ($x) fs) xs

apply :: ListF a b -> [a] -> b
apply f xs = headF (partialApply f xs)

Например,sum функцию можно рассматривать как переменную функцию:

sumF :: Num a => ListF a a
sumF = Cons 0 (mapF (+) sumF)

sumExample = apply sumF [3, 4, 5]

Однако мы также хотим иметь возможность работать с обычными функциями, которые не обязательно знают, что делать с любым количеством аргументов. Так что делать? Ну, как Лисп, мы можем генерировать исключение во время выполнения. Ниже мы будем использоватьf в качестве простого примера невариантной функции.

f True True True  = 32
f True True False = 67
f _ _ _ = 9

tooMany = error "too many arguments"
tooFew  = error "too few arguments"
lift0 v = Cons v tooMany
lift1 f = Cons tooFew (lift0 f)
lift2 f = Cons tooFew (lift1 f)
lift3 f = Cons tooFew (lift2 f)

fF1 = lift3 f

fExample1 = apply fF1 [True, True, True]
fExample2 = apply fF1 [True, False]
fExample3 = apply (partialApply fF1 [True, False]) [False]

Конечно, если вам не нравится шаблон определенияlift0, lift1, lift2, lift3и т. д. отдельно, тогда вам нужно включить некоторые расширения. Но вы можете получить довольно далеко без них!

Вот как вы можете обобщить на одинlift функция. Сначала мы определим несколько стандартных чисел уровня типа:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, TypeFamilies, UndecidableInstances #-}

data Z = Z
newtype S n = S n

Затем введите класс типов для подъема. Вы должны прочитать типI n a b как "n копииa в качестве аргументов, то возвращаемый типb».

class Lift n a b where
    type I n a b :: *
    lift :: n -> I n a b -> ListF a b

instance Lift Z a b where
    type I Z a b = b
    lift _ b = Cons b tooMany

instance (Lift n a (a -> b), I n a (a -> b) ~ (a -> I n a b)) => Lift (S n) a b where
    type I (S n) a b = a -> I n a b
    lift (S n) f = Cons tooFew (lift n f)

А вот примеры использованияf прежде, переписать с использованием обобщенного лифта:

fF2 = lift (S (S (S Z))) f

fExample4 = apply fF2 [True, True, True]
fExample5 = apply fF2 [True, False]
fExample6 = apply (partialApply fF2 [True, False]) [False]

f а такжеf x разные типы. Из-за статически типизированной природы haskell он не может выполнять никаких функций. Это должно принять определенный тип функции.

предполагатьf передается с типомa -> b -> c, затемf x имеет типb -> c, Ноa -> b -> c должен иметь тот же тип, что иa -> b, Следовательно, функция типаa -> (b -> c) должна быть функцией типаa -> b, Такb должен быть таким же, какb -> c, который является бесконечным типомb -> b -> b -> ... -> c, Этого не может быть. (продолжать заменятьb -> c заb)

 Ben Millwood20 сент. 2012 г., 20:57
Ответ является неточным, поскольку это бесконечное расширение типа является неправильным, но я не одобряю, а просто поправляю, потому что остальная часть ответа также смущает.
Решение Вопроса

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

Используя отражение

Мы можем отложить проверку типа приложения до времени выполнения:

import Data.Dynamic
import Data.Typeable

apply :: Dynamic -> [Dynamic] -> Dynamic
apply f []      = f
apply f (x:xs)  = apply (f `dynApp` x) xs

Обратите внимание, что теперь программа на Haskell может завершиться с ошибкой типа во время выполнения.

По типу рекурсии

Используя полустандартText.Printf хитрость (придуманная augustss, IIRC), решение может быть закодированов этом стиле (упражнение). Это может быть не очень полезно, и все же требует некоторой хитрости, чтобы скрыть типы в списке.

Изменить: я не мог придумать способ написать это, без использования динамических типов или списков / экзистенциалов. Хотелось бы увидеть пример

 C. A. McCann15 авг. 2011 г., 15:33
В некотором роде к игре на данный момент, новот очень простая версия такого рода вещей что делает вариационное применение к вложенным кортежам (а ля HList) или значениям из списка (если аргументы функции имеют однородный тип). Мягко интересно, что он использует только семейства типов, а не fundeps.

Ваш ответ на вопрос