应用函子 - Haskell

问题描述 投票:0回答:2

pure (+)  <*> (Just 1) <*> (Just 2)

上面表达式的展开是否正确?

pure (+)  <*> (Just 1) <*> (Just 2)
= (Just (+)) <*> (Just 1) <*> (Just 2)
= (Just (1+)) <*> (Just 2)
= Just 3

如果是这样,那为什么我们不能这样做

(Just (+)) <*> (Just 2)

haskell applicative
2个回答
2
投票

相信您已经在评论中回答了您的问题。所以只是为了完成......

(Just (+)) <*> (Just 2)
是 REPL 无法打印的部分应用函数,并给出错误:

• No instance for (Show (Integer -> Integer)) arising from a use of ‘print’
,

但除此之外还好。


这里没问题:

> :t (Just (+)) <*> (Just 2)

(Just (+)) <*> (Just 2) :: Num a => Maybe (a -> a)
.


完成功能也不错:

> f = (Just (+)) <*> (Just 2)

> f <*> Just 1

> Just 3

你的理解似乎完全正确。


顺便说一句,另一种写法是:

(+) <$> (Just 1) <*> (Just 2)


1
投票

扩展确实是正确。表情

pure (+) <*> Just 1 <*> Just 2

相当于:

(+) <$> Just 1 <*> Just 2

和:

liftA2 (+) (Just 1) (Just 2)

不仅适用于

Maybe
,还适用于任何
Applicative
类型。

“机械”扩展是首先查看表达式,这里是表达式

pure (+) <*>1 Just 1 <*>2 Just 2

相当于:

(<*>2) ((<*>1) (pure (+)) (Just 1)) (Just 2)

我添加了下标来跟踪

<*>
的两种用法。此时我们不知道
Applicative
实例
pure
会“选择”什么,但这将根据“类型传播”来确定。

外部

(<*>)
,因此
(<*>2)
具有类型
Applicative f => f (a -> b) -> f a -> f b
,对于内部类型,我们选择
(<*>1) :: Applicative g => g (c -> d) -> g c -> g d
。两者中的第二个操作数是
Num m => Maybe m
Num n => Maybe n
。因此,这意味着
f
g
都将与
f ~ g ~ Maybe
匹配。

这也意味着

pure
将采用
Maybe
Applicative
实例,这意味着
pure
相当于
Just
,因此在这种情况下
pure (+)
将是
Num o => Just (o -> o -> o)
。如果我们将其与内部
(<*>)
的类型相匹配,则表示
o ~ m
,而与外部
(<*>)
的类型相匹配,则表示
o ~ m ~ n
。所以表达式的类型将是:

pure (+) <*> Just 1 <*> Just 2 :: Num m => Maybe m

而对于扩展,我们可以将

pure
替换为
Just
,所以:

Just (+) <*> Just 1 <*> Just 2

然后

Just (+) <*> Just 1
将转换为
Just (1 +)
,因为两个操作数都是
Just
,并且操作数实现为:

instance Applicative Maybe where
    pure = Just

    Just f  <*> m       = fmap f m
    Nothing <*> _m      = Nothing

最后

Just (1 +) <*> Just 2
,工作原理相同,所以:

Just (1 + 2)

相当于:

Just 3

如果是这样,那为什么我们不能这样做

(Just (+)) <*> (Just 2)

我们可以,我们只是不能

show
结果。
Just (+) <*> Just 2
的结果将是
Just (2 +)
,所以这是一个函数,并且函数不能显示(默认情况下)。

但是我们可以这样做:

ghci> Just (1 +) <*> Just 2
Just 3

或者我们可以使用

Just (+) <*> Just 2
的结果来处理第二个操作数:

ghci> (Just (+) <*> Just 2) <*> Just 3
Just 5

括号在这里不是必需的,但用于使表达式的解读方式更加明确。

© www.soinside.com 2019 - 2024. All rights reserved.