Haskell:之前的 return 被之后的 monad 抵消了。如何?

Haskell: a return before is cancelled out by a monad after. How?

如何理解 return 1 getLine 语句?它通过了类型检查,看起来与 1 相同。 getLinereturn 如何相互“抵消”?这对我来说完全没有意义。

Prelude> :t return 1
return 1 :: (Monad m, Num a) => m a

Prelude> :t return 1 getLine            -- why is it not a type error?
return 1 getLine :: Num t => t          

Prelude> return 1 getLine               
1                                       -- whatever happened to getLine?

此外,为什么最终产品是“纯”的,即使它涉及 getLine

如果你写return 1 getLine,那意味着return 1应该是一个以getLine为参数的函数。

我们很幸运,因为有一个instance for Monad with a function ((->) r) [src]。确实:

-- | @since 2.01
instance Applicative ((->) r) where
    pure = const
    (<*>) f g x = f x (g x)
    liftA2 q f g x = q (f x) (g x)

-- | @since 2.01
instance Monad ((->) r) where
    f >>= k = \ r -> k (f r) r

(->) rr -> … 的更规范的形式。因此它是一个以 r 作为参数类型的函数,如果应用于类型参数 a 例如,则 ((->) r) a 等同于 r -> a.

对于 Monad 的这个实例,returnpure 具有相同的实现,即 const。因此,这意味着:

return 1 getLine

相当于:

   const 1 getLine
→ (\_ -> 1) getLine
→ 1

How do I understand the statement return 1 getLine?

首先注意到 return 1 getLine 实际上是 (return 1)getLine.

这意味着 return 1 是一个函数,因为它接受一个额外的参数,并且函数也是一元值 (这就是为什么它不是类型错误)

所以我们必须统一

return   ::  Monad m   => a  -> m  a
return 1 :: (Monad m, Num a) => m  a
return 1 ::           Num a  => r -> a     -- Monad (r ->)

所以 m a ~ r -> am ~ (->) r (这是写 (r ->) 的正确方法,它本身就是一个无效的语法)。

对于函数,return = const 所以我们有

return 1 getline 
= const 1 getline 
= const 1 undefined
= 1

因为const定义为

const :: a -> b -> a
const    x    y =  x

(这就是 getLine 被忽略的方式)。


一般来说,函数 Monad 实例的定义使得

do { a <- f ; b <- foo a ; return (bar a b) } x

相同
let { a = f x ; b = foo a x } in bar a b  -- const (bar a b) x

这就是 return 被定义为 const 的原因。

这意味着 returngetLine 而不是 “相互抵消”。这只是 return 所做的,因为它被应用于第二个参数, 不管是什么 ,即使是 undefined.

所以 getLine 属于 IO “monad”,正如您在问题中所写的那样, 无关 。 Haskell 中的一切都是一个值,getLine 也只是另一个值。这是一个纯粹的价值;它只是描述了一个“不纯”的 I/O 动作,但它本身只是另一个值,在这里仅用作参数。只有当 getLine 出现在 main 的适当位置(或者在 main 中递归出现的其他代码中)时,它才是“运行”,即它描述的计算才真正执行。这里不是这样的。

这里使用的 monad 是这个 return 所属的函数 monad。


至于纯度问题,单子本身既不是纯的也不是不纯的。实现 Monad 的类型可以是 不纯。函数恰好是纯的。

Monad 所做的是分离 纯与潜在的不纯。

但这实际上也是函子所做的。 Monads,具体来说,允许混合链接 pure-->impure-->pure-->impure-->....位,同时保持它们的分离(同样,“不纯”位实际上也可以是纯的;重要的是两个“世界”之间的分离)。