8

所以我有一个类型的两个参数的函数列表[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

我认为逻辑是正确的,它只是不进行类型检查。

提前致谢!

4

2 回答 2

8

来自 nm 的评论是正确的——这不能以任何传统方式完成,因为结果的类型取决于输入列表的长度。你需要一个更高级的类型系统来完成这项工作。你可以在 Haskell 中妥协,使用一个在类型中编码它的长度的列表,但这既痛苦又尴尬。

相反,由于您的参数都是相同的类型,因此创建一个接受值列表而不是多个参数的函数会更好。所以你想要的类型是这样的:chain :: [a -> a -> a] -> [a] -> a

有几种方法可以编写这样的函数。从概念上讲,您希望从参数列表的前面和函数列表的末尾开始,然后将第一个函数应用于第一个参数以获得 type 的东西a -> a。从那里,将该函数应用于下一个参数,然后将下一个函数应用于结果,从每个列表中删除一个元素并为您提供一个 type 的新函数a -> a

您还需要处理列表长度不正确匹配的情况。除了前面提到的类型编码长度和与之相关的麻烦之外,没有办法解决这个问题。

于 2011-12-08T18:10:19.490 回答
1

我想知道,您的“具有功能列表”要求是真正的要求还是解决方法?我遇到了同样的问题,但在我的情况下,函数集很小并且在编译时已知。更准确地说,我的任务是用 xor 压缩 4 个列表。我想要的只是一个紧凑的符号来组成 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]

这并没有按原样回答原始问题,但希望仍然会有所帮助,因为它几乎涵盖了问题主题行的内容。

于 2014-02-16T02:00:35.647 回答