Haskell中的函数组合

时间:2012-12-05 03:59:00

标签: haskell

我有一个函数,它接受3个函数并将它们组合起来改变列表参数。

例如,测试用例调用将是:链初始化尾部反向“Haskell!”输出应为 lleksa

我尝试过几种不同的方式来解决这个问题,包括使用map函数,但我一直遇到关联问题。所以我做了

chain :: Ord a => [a] -> a
chain f g h x = f.g.h$x

,错误为Couldn't match expected type [t0 -> t1 -> t2 -> a0]

当我直接在GHCi中输入问题时,例如写init.tail.reverse$"Haskell!"它可以正常工作

有没有办法包含三个函数参数?我在例子中只看到过两个。

3 个答案:

答案 0 :(得分:6)

组成3个函数的高阶函数的最通用类型签名是:

chain :: (b -> c) -> (b1 -> b) -> (a -> b1) -> a -> c
chain f g h x = f.g.h$x

(您也可以在不使用x的情况下编写定义,只需

chain f g h = f.g.h

)。请注意,中间函数bb1的返回类型是任意的,唯一的要求是它们必须匹配下一个函数的参数类型。现在,如果您致电chain init tail reverse "Haskell!",您将获得"lleksa"

如果您知道如何编写函数,但您不知道其正确的类型,则可以让GHCi为您推断出类型。只需加载该函数并输入例如:t chain:t:type的简写,请参阅GHCi commands)。


你可以更进一步,组成任意数量的功能。 (但在这种情况下,类型系统会强制您使用一般类型的签名。)

chainN :: [a -> a] -> (a -> a)
chainN fs = foldr (.) id fs

此函数从aa获取函数列表并将它们组合在一起。如果列表为空,则仅返回标识函数。使用chainN,您可以编写类似

的内容
chainN [init, tail, reverse] "Haskell!"

答案 1 :(得分:1)

当前奏“看起来”你的功能时:

chain f g h x = f.g.h$x

它假设您正在接收函数f g和h。为什么假设f g h是功能?因为.运算符的唯一目的是链函数。所以如果你使用它是因为你是连锁函数。

您为函数([a] -> a)定义了一个类型签名,该签名与您的函数应该接收和返回的类型签名不同。它的一个解决方案是不指定类型签名并让它前置,另一个解决方案是更正类型签名。

但如果你希望你的函数接收'a'列表并返回'a',你应该修改或运行这样的东西:

chain :: (Ord a) => [a] -> a
chain (x:xs) = ...

答案 2 :(得分:0)

  

有没有办法包含三个函数参数?我在例子中只见过两个。

您应该查看您阅读的任何介绍材料,或者如果可以的话,可以选择一些介绍材料。你似乎很困惑。

  

当我直接在GHCi中输入问题时,例如写init.tail.reverse$"Haskell!"它可以正常工作

您可以使用ghci查找表达式的类型。

λ:> chain f g h x = f.g.h$x
λ:> :t chain
chain :: (b1 -> c) -> (b2 -> b1) -> (a -> b2) -> a -> c

这只是

的专业化
chain :: ([a] -> [a]) -> ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]

我猜是你想写的。

对于它的价值,如果您只是在列表上工作,您可能会想要以下内容。

chain :: [[a] -> [a]] -> [a] -> [a]
chain = foldr (.) id

旋转GHCi:

λ:> chain = foldr (.) id
λ:> chain [init, tail, reverse] "Haskell!"
"lleksa"

你得到了我猜你想要的结果。如果您还不了解其工作原理,请不要担心,并坚持使用其他解决方案,并在您准备好后再回来。