实现咖喱功能

问题描述:

我目前正在阅读由Graham Hutton编写的“haskell编程”,并且刚刚达到了咖喱和功能组合。在练习部分中,有一项任务是从零开始实施咖喱功能,这已经存在于前奏中模块。实现咖喱功能

这里是我的实现,但它不是working.Can人解释(我是新来的函数式编程),为什么它不工作

my_curry :: ((a ,b) -> c) -> (a -> b -> c) 
my_curry origFunc = origFunc.combine 
        where 
         combine e f = (e, f) 

这里的错误[添加]

[1 of 1] Compiling Main    (higher_order.hs, interpreted) 

    higher_order.hs:92:30: 
     Couldn't match type `t0 -> (a, t0)' with `(a, b)' 
     Expected type: a -> (a, b) 
     Actual type: a -> t0 -> (a, t0) 
     In the second argument of `(.)', namely `combine' 
     In the expression: origFunc . combine 
     In an equation for `my_curry': 
      my_curry origFunc 
      = origFunc . combine 
      where 
       combine e f = (e, f) 
+0

-1 - “不工作”没有意义。澄清你的意思:1)代码是否编译? (如果不是,你为什么不发布你得到的错误?)2)程序是否返回意外的结果? (你为什么不公布你得到的结果和你期望的结果?)3)程序是否以其他方式崩溃或失败? (你为什么不描述它?)。 – Bakuriu 2014-08-28 18:05:24

+0

只需注意,如果您对代码的错误信息(即错误消息是什么)给出了更多详细信息,您将来可以更迅速地得到答案。否则,我们都必须弄清楚什么是错的,然后修复它,但这并不总是可行的。 – jozefg 2014-08-28 18:08:06

问题是.是为了拿单参数的函数,并将它们粘合在一起,

在这种情况下combine的类型为a -> b -> (a, b)。所以它的第一个参数是a,它的返回类型是b -> (a, b)(记得->组右侧)。所以.有型

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

由于combine是第二个参数Haskell是要统一像

(.).a ~ combine.a 
(.).b ~ (combine.b -> (combine.a, combine.b)) 

我使用foo.bar. S型变量来自定义指的是类型变量barfoo。接下来我们将其作为类型(a, b) -> c填入origFunc。现在,当我们尝试将其合并到.时,我们得到了

(.).b ~ my_curry.(a, b) 
(.).c ~ my_curry.c 

但是等等! b不能同时为(a, b)b -> (a, b),因此类型错误。

相反,我们有两个选择,我们可以创建一个新的类型的组成

(..) :: (c -> d) -> (a -> b -> c) -> a -> b -> d 
f .. g = \a b -> f (g a b) 

注意如何让g取两个参数,和你的功能变得

my_curry origFunc = combine .. origFunc 

,或者我们可以只使用currying

my_curry origFunc x y = origFunc (x, y) 
+0

另一种做这种构图的方法是'my_curry origFunc =(origFunc。)。 combine'。 – 2014-08-29 01:40:11

+0

@JohnL当然,我不确定这对Haskell初学者是否合适 – jozefg 2014-08-29 01:43:29

jozefg的答案解释了为什么你的代码不起作用,我想我会为你提供一个相当直接的实现。

请注意my_curry的函数签名是((a, b) -> c) -> (a -> b -> c)。它接受一个函数,并返回一个函数作为结果。我们可以用一个lambda表达式轻易俘获的“返回一个函数”的概念:

my_curry func = \x y -> func (x, y) 

所有这些代码确实是发生在左侧等号的单一功能,并在返回一个新功能右侧。它返回的函数一次只取一个参数,对它们进行元组化,并将它们传递给我们传入的任何函数。

我们可以看到的另一种方法是删除类型签名中的括号。由于类型签名中的箭头是右关联的,因此my_curry的类型也可以写为((a, b) -> c) -> a -> b -> c。在这种形式下,我们可以看到我们也可以实现my_curry作为一个函数,它有三个参数:输入函数,以及x和y来元组化并通过该函数发送。因此,写功能的另一个有效办法是

my_curry func x y = func (x, y)