Haskell中的函数合成

Haskell中的函数合成,haskell,Haskell,我有一个函数,它接受3个函数,并将它们组合起来改变一个列表参数 例如,一个测试用例调用是:chain init tail reverse“Haskell!”输出应该是lleksa 我尝试了几种不同的方法来解决这个问题,包括使用map函数,但我一直遇到关联问题。所以我做了 chain :: Ord a => [a] -> a chain f g h x = f.g.h$x 错误是无法匹配预期的类型[t0->t1->t2->a0] 当我直接在GHCi中输入问题时,比如写,init.ta

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

例如,一个测试用例调用是:chain init tail reverse“Haskell!”输出应该是lleksa

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

chain :: Ord a => [a] -> a
chain f g h x = f.g.h$x
错误是
无法匹配预期的类型[t0->t1->t2->a0]

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


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

当prelude分析您的函数时:

chain f g h x = f.g.h$x
它假定您正在接收函数
f
g
h
。为什么会这样假设?因为
操作符的目的是链接函数。因此,如果您使用它,是因为您正在链接函数

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

但是,如果您希望函数接收
a
列表并返回
a
,则应将函数修改为以下内容:

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

当prelude分析您的功能时:

chain f g h x = f.g.h$x
它假定您正在接收函数
f
g
h
。为什么会这样假设?因为
操作符的目的是链接函数。因此,如果您使用它,是因为您正在链接函数

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

但是,如果您希望函数接收
a
列表并返回
a
,则应将函数修改为以下内容:

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

对于由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
的缩写,请参阅)


您可以更进一步,由任意数量的函数组成。(但在这种情况下,类型系统会强制您少使用一些常规类型签名。)

此函数获取从
a
a
的函数列表,并将它们组合在一起。如果列表为空,则只返回identity函数。使用
chainN
可以编写如下内容

chainN [init, tail, reverse] "Haskell!"

对于由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
的缩写,请参阅)


您可以更进一步,由任意数量的函数组成。(但在这种情况下,类型系统会强制您少使用一些常规类型签名。)

此函数获取从
a
a
的函数列表,并将它们组合在一起。如果列表为空,则只返回identity函数。使用
chainN
可以编写如下内容

chainN [init, tail, reverse] "Haskell!"
有没有办法包含三个函数参数?我在示例中只看到了两个

你可能应该复习你读过的任何介绍性材料,或者尽可能地挑选一些介绍性材料。你似乎很困惑

当我直接在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"
你得到了我猜你想要的结果。如果您还不明白这是如何工作的,不要担心,坚持使用其他解决方案,并在您准备好时返回

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

你可能应该复习你读过的任何介绍性材料,或者尽可能地挑选一些介绍性材料。你似乎很困惑

当我直接在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]
我猜这就是你想写的

无论如何,你可能会