当前位置:  开发笔记 > 编程语言 > 正文

Haskell组成有两个参数

如何解决《Haskell组成有两个参数》经验,为你挑选了2个好方法。

我试图通过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

我不知道我做错了什么.

你能帮我理解一下这个错误,以便找到解决方案吗?



1> Frerich Raab..:

给定一个功能

add :: Integer -> Integer -> Integer

记住(正如你在" 我理解的内容"部分中指出的那样),->类型签名与右侧相关联,即上述类型与

add :: Integer -> (Integer -> Integer)

现在,考虑以下类型(.):

(.) :: (b -> c) -> (a -> b) -> a -> c

这意味着在表达式中

(.) add

b在的类型(.)IS Integerc对应于Integer -> Integer.写这个的另一种方法是

b ~ Integer
c ~ Integer -> Integer

所以我们得到了

(.) add :: (a -> Integer) -> a -> (Integer -> Integer)

如果你现在申请(.) addsub的是,编译器会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

对于它的价值,存在一个相关的问题:用一个参数函数组成一个两个参数函数,例如组合



2> Zeta..:

我希望能够撰写它们.它没有任何意义,但这是一个学习目标.

这实际上是问题所在.你想怎么写他们?让我们看看一些可能的成分:

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如果这种功能是你最初的目标,你最好写一个明确的定义.

推荐阅读
贴进你的心聆听你的世界
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有