我有一个函数,它接受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!"
它可以正常工作
有没有办法包含三个函数参数?我在例子中只看到过两个。
答案 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
)。请注意,中间函数b
和b1
的返回类型是任意的,唯一的要求是它们必须匹配下一个函数的参数类型。现在,如果您致电chain init tail reverse "Haskell!"
,您将获得"lleksa"
。
如果您知道如何编写函数,但您不知道其正确的类型,则可以让GHCi为您推断出类型。只需加载该函数并输入例如:t chain
(:t
是:type
的简写,请参阅GHCi commands)。
你可以更进一步,组成任意数量的功能。 (但在这种情况下,类型系统会强制您使用一般类型的签名。)
chainN :: [a -> a] -> (a -> a)
chainN fs = foldr (.) id fs
此函数从a
到a
获取函数列表并将它们组合在一起。如果列表为空,则仅返回标识函数。使用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"
你得到了我猜你想要的结果。如果您还不了解其工作原理,请不要担心,并坚持使用其他解决方案,并在您准备好后再回来。