Составление цепочки функций с двумя аргументами - PullRequest
8 голосов
/ 08 декабря 2011

Итак, у меня есть список функций двух аргументов типа [a -> a -> a]

Я хочу написать функцию, которая возьмет список и скомпонует их в цепочку функций, которая принимает длину + 1аргументы составлены слева.Например, если у меня есть [f,g,h] всех типов [a -> a -> a], мне нужно написать функцию, которая дает:

chain [f,g,h] = \a b c d -> f ( g ( h a b ) c ) d

Также, если это помогает, функции являются коммутативными в своих аргументах (то есть f x y = f y x длявсе x y).

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

Это то, что я до сих пор:

f xs = f' xs
    where
        f' []   = id
        f' (x:xs) = \z -> x (f' xs) z

Я думаю, логика идет по правильному пути, он просто не проверяет тип.

Заранее спасибо!

Ответы [ 2 ]

8 голосов
/ 08 декабря 2011

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

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

Существует несколько способов написания такой функции.Концептуально вы хотите начать с начала списка аргументов и конца списка функций, а затем применить первую функцию к первому аргументу, чтобы получить что-то типа a -> a.Затем примените эту функцию к следующему аргументу, затем примените следующую функцию к результату, удалив по одному элементу из каждого списка и предоставив вам новую функцию типа a -> a.

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

1 голос
/ 16 февраля 2014

Интересно, является ли ваше требование «иметь список функций» реальным требованием или обходным путем? Я столкнулся с той же проблемой, но в моем случае набор функций был небольшим и известным во время компиляции. Чтобы быть более точным, моя задача состояла в том, чтобы сжать 4 списка с помощью xor. И все, что я хотел, это компактная запись для составления 3-х двоичных функций. Я использовал маленький помощник:

-- Binary Function Chain
bfc :: (c -> d) -> (a -> b -> c) -> a -> b -> d
bfc f g = \a b -> f (g a b)

Например:

ghci> ((+) `bfc` (*)) 5 3 2 -- (5 * 3) + 2
17
ghci> ((+) `bfc` (*) `bfc` (-)) 5 3 2 1 -- ((5 - 3) * 2) + 1
5
ghci> zipWith3 ((+) `bfc` (+)) [1,2] [3,4] [5,6]
[9,12]
ghci> getZipList $ (xor `bfc` xor `bfc` xor) <$> ZipList [1,2] <*> ZipList [3,4] <*> ZipList [5,6] <*> ZipList [7,8]
[0,8]

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

...