1

我有一个函数,它需要 3 个函数并将它们组合起来以更改列表参数。

例如,一个测试用例调用是:chain init tail reverse "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!"它可以正常工作

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

4

3 回答 3

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 命令)。


你可以更进一步,组合任意数量的函数。(但在这种情况下,类型系统会强制您使用不那么通用的类型签名。)

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

此函数从ato获取函数列表a并将它们组合在一起。如果列表为空,则仅返回标识函数。有了chainN你可以写的东西像

chainN [init, tail, reverse] "Haskell!"
于 2012-12-05T08:25:35.150 回答
1

当 Prelude 分析你的功能时:

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

它假定您正在接收函数fgh。为什么会这样假设?因为.运算符的目的是链接函数。因此,如果您使用它是因为您正在链接函数。

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

但是,如果您希望您的函数接收a并返回一个列表,a您应该将您的函数修改为如下所示:

chain :: (Ord a) => [a] -> a
chain (x:xs) = ...
于 2012-12-05T04:56:18.200 回答
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"

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

于 2017-09-09T06:49:45.377 回答