我试图通过Haskell理解函数式编程,并且我在处理函数组合时遇到了很多麻烦.
其实我有这两个功能:
add:: Integer -> Integer -> Integer add x y = x + y sub:: Integer -> Integer -> Integer sub x y = x - y
我希望能够撰写它们.它没有任何意义,但这是一个学习目标.
我尝试过的:
foo:: (Integer -> Integer) -> (Integer -> Integer) -> Integer foo = add . sub
我明白了:
Haskell使用只有一个args的函数,因此我们返回一个新函数,在每次执行函数后执行.
所以第一个Integer
是param类型,而第二个是生成函数的返回类型,必须添加第二个数字.
这将返回另一个函数(sub
),它将产生相同的流程(返回带有参数等的函数...)
我对吗 ?
这是我的实际错误代码:
src\Main.hs:23:7: Couldn't match type `Integer' with `Integer -> Integer' Expected type: Integer -> (Integer -> Integer) -> Integer Actual type: Integer -> Integer -> Integer In the first argument of `(.)', namely `add' In the expression: add . sub src\Main.hs:23:13: Couldn't match type `Integer -> Integer' with `Integer' Expected type: (Integer -> Integer) -> Integer Actual type: Integer -> Integer -> Integer Probable cause: `sub' is applied to too few arguments In the second argument of `(.)', namely `sub' In the expression: add . sub
我不知道我做错了什么.
你能帮我理解一下这个错误,以便找到解决方案吗?
给定一个功能
add :: Integer -> Integer -> Integer
记住(正如你在" 我理解的内容"部分中指出的那样),->
类型签名与右侧相关联,即上述类型与
add :: Integer -> (Integer -> Integer)
现在,考虑以下类型(.)
:
(.) :: (b -> c) -> (a -> b) -> a -> c
这意味着在表达式中
(.) add
该b
在的类型(.)
IS Integer
和c
对应于Integer -> Integer
.写这个的另一种方法是
b ~ Integer c ~ Integer -> Integer
所以我们得到了
(.) add :: (a -> Integer) -> a -> (Integer -> Integer)
如果你现在申请(.) add
到sub
的是,编译器会a -> Integer
无法进行匹配Integer -> Integer -> Integer
.
我怀疑你可能希望组合有三个参数:两个要应用sub
,然后结果与第三个参数一起传递给add
.因此,构成这两个函数的可能定义是
foo :: (Integer -> Integer -> Integer) -> (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer foo f g x y = f (g x y) y
对于它的价值,存在一个相关的问题:用一个参数函数组成一个两个参数函数,例如组合
我希望能够撰写它们.它没有任何意义,但这是一个学习目标.
这实际上是问题所在.你想怎么写他们?让我们看看一些可能的成分:
foo x y = sub x (add x y) -- x + y - x = y foo x y = sub y (add x y) -- x + y - y = x foo x y = sub x (add y y) -- 2 * y - x foo x y = sub y (add y y) -- 2 * y - y = y foo x y = sub y (sub y (add x x)) -- 2 * x - 2 * y
话虽这么说,让我们通过检查手中的类型来检查类型错误:
type I = Integer -- otherwise the lines are going to be very long (.) :: (b -> c ) -> (a -> b ) -> a -> c add :: I -> (I -> I) sub :: I -> (I -> I) -- ||||||||||||| (.) add :: (a -> I ) -> a -> (I -> I) -- ^^^^^^^^^^^^^
如您所见,(.) add
已经强制要求其他函数只能具有a -> Integer
任意类型a
.但是sub
类型是Integer -> (Integer -> Integer)
(记住,(->)
是正确的关联).
现在,你能做些什么才能真正解决这个问题?首先,让我们检查您提出的类型foo
:
foo :: (Integer -> Integer) -> (Integer -> Integer) -> Integer
这实际上是一种非常有趣的功能.你怎么会得到你的结果?你手头有两个函数,但没有值:
> foo f g =
您可以使用其中一个函数的固定点解决此问题,然后应用另一个函数:
> let x = f x in g x > > example = foo (const 12) (+1) -- returns 13
但这不是你的意思,对吗?在这一点上,考虑你的作品的语义是非常重要的.由于这些不清楚,你不能写一般的方法来组合这两个功能.
但是,如果你真正的意思
foo :: Integer -> Integer -> Integer -> Integer foo x y z = add (sub x y) z
然后就可以了
foo = (add .) . sub
以来
(.) add :: (a -> I) -> a -> (I -> I) (.) ((.) add) :: (a -> b -> Integer) -> a -> b -> Integer -> Integer
但是(add .) . sub
再也不容易了.foo
如果这种功能是你最初的目标,你最好写一个明确的定义.