微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Haskell:无咖喱,咖喱,成分

如何解决Haskell:无咖喱,咖喱,成分

输入此代码时,我对理解编译器的工作存在疑问:

(curry . uncurry) (+) 1 2 

据我了解,编译器首先使用uncurry,这意味着会发生错误,因为uncurry函数需要这样的输入:

(curry . uncurry) (+) (1,2)

但是显然第一个是对的。我不明白为什么。

编译器对此进行评估时究竟要采取什么步骤?

一个主题包括以下问题: 为什么

(uncurry . curry) (+) (1,2) 

不起作用?

解决方法

据我了解,编译器不费吹灰之力。

否,(curry . uncurry)

如果我们评估(curry . uncurry)函数,我们将看到以下缩写:

\x -> curry (uncurry x)

所以(curry . uncurry) (+) 1 2函数的缩写为:

(\x -> curry (uncurry x)) (+) 1 2

或因此:

(curry (uncurry (+))) 1 2

uncurry :: (a -> b -> c) -> (a,b) -> ccurry :: ((a,b) -> c) -> a -> b -> c从而转换一个函数。因此,这意味着uncurry (+)实际上期望一个2元组:

uncurry (+) :: Num a => (a,a) -> a

但现在通过curry函数传递此函数:

curry (uncurry (+)) :: Num a => a -> a -> a

因此curry函数撤消了uncurry(+)函数的转换。因此,这意味着curry (uncurry (+))(+)相同,因此:

(curry (uncurry (+))) 1 2

等效于:

(+) 1 2

,因此等同于3

curry . uncurry并不完全等同于id,因为它具有以下类型:

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

因此,这意味着它将功能限制为类型a -> (b -> c)的功能。

,

您的表达式解析为

(((curry . uncurry) (+)) 1) 2

因此,它将构建函数(curry . uncurry) (+)并将其应用于1,然后将结果函数应用于2

因此,我们从(curry . uncurry) (+)开始,这意味着curry (uncurry (+))。为简单起见,假设(+)的实现方式为

(+) = \x y -> ...

请注意,上面是一个咖喱函数,以x然后以y作为单独的参数。然后我们有:

curry (uncurry (+))
= { definition + }
curry (uncurry (\x y -> ...))    -- note the separate arguments
= { definition uncurry }
curry (\(x,y) -> ...)           -- only one pair argument
= { definition curry }
(\x y -> ...)                    -- back to two arguments
= { definition + }
(+)

以上,uncurry将函数+转换为一个接受单个对参数而不是两个对的参数。 curry颠倒了这种转换过程,它将对参数分成两个独立的参数。

实际上,curry . uncurry是对二进制咖喱函数的身份转换,因为它应用了转换及其逆运算。因此,它对结果或所涉及函数的类型没有影响。

我们得出结论,您的表达式等同于((+) 1) 2,其结果为3

,

这个问题得到了很好的答案,但我想添加关于curry . uncurry的注释。

您可能听说过SKI-微积分。如果您还没有,那是我们与3个组合器一起工作的一个演算:

Sabc = ac(bc)
Kab  = a
Ia   = a

众所周知,图灵满满。

此外,I组合器是多余的。让我们尝试根据SK组合器写下来。 主要思想是应将I的唯一参数作为K的第一个参数传递,该参数的第二个参数被占用。正是S组合器所做的:如果将K作为S的第一个参数传递,我们将让它返回S的第三个参数:

SKbc = Kc(bc) = c

我们已经证明(K*ab = b):

K* = SK

因此,我们只需要选择第二个参数:KS都可以:

I = SKK = SKS

正如人们所看到的,组合器I对应于id; 组合器K对应于const; 组合器S对应于(<*>) :: (e -> a -> b) -> (e -> a) -> e -> b

I = SKK对应于const <*> const :: a -> a。 由于输入以下内容,我们的其他结果(I = SKSK* = SK在Haskell中不成立:

GHCi> :t (<*>) const (<*>) {- id -}
(<*>) const (<*>) {- id -}
  :: Applicative f => f (a -> b) -> f (a -> b)

GHCi> :t (const <*>) {- flip const -}
(const <*>) {- flip const -} :: (b -> a) -> b -> b

正如人们所看到的,我们的实现在它们的域中充当必需的功能,但是我们缩小了域的范围。

如果我们向读者指定(<*>) const (<*>),我们将得到您记为curry . uncurry-id的函数。

curry . uncurry的另一种方法是($)

f $ x   = f x
($) f x = f x
($) f   = f
($)     = id

您发现的功能非常有趣-寻找其他类似工作可能是一个好习惯(我不知道那里是否还有其他值得注意的工作)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。