何时使用或不使用Haskell的monad表达式中的'return'

pro*_*eek 1 monads haskell

我有一个函数a 1)计算(argument+) argument,2)加倍它(解释Haskell monad例子).

a :: Int -> Int 
a = (id >>= (\n -> (n+))) >>= (\d -> return (d + d))
Run Code Online (Sandbox Code Playgroud)

在这个函数中,我应该使用return来防止错误.

但是在这个三重函数中,返回((argument+) argument)+ argument)三倍的输入参数.我不能用退货.

triplex :: Int -> Int 
triplex = (id >>= (\n -> (n+))) >>= (\d -> (d+))
Run Code Online (Sandbox Code Playgroud)

从这些例子中,我想简单的规则return是1)我们return在返回值时使用,2)return当我们返回部分函数时我们不使用.但我不确定这是正确的理解.那么,returnHaskell 背后有这样的规则吗?

Ale*_*ing 8

returnHaskell中的函数与return命令式编程语言中的关键字几乎没有关系- 它只是一个普通类型签名的普通函数:

return :: Monad m => a -> m a
Run Code Online (Sandbox Code Playgroud)

基本上,return取任何旧的价值,并将其"提升"为monad.当你m用一个具体的类型替换这个函数时,它会更清楚一些,例如Maybe:

return :: a -> Maybe a
Run Code Online (Sandbox Code Playgroud)

这里只有一个实现上述功能的,这就是Just,这样return = JustMaybe单子.

在您的情况下,您使用的是monad函数(->) r,通常也称为"reader"monad.执行与之相同的替换Maybe,我们得到以下签名:

return :: a -> r -> a
Run Code Online (Sandbox Code Playgroud)

这个函数只有一个实现,即忽略它的第二个参数并返回它的第一个参数.这是什么const,所以return = const对功能.


"何时使用return"的问题是合理的,但在理解了上述内容后应该更有意义:return当传递给函数返回的值>>=不是monadic时,需要使用它,因此需要"解除".例如,以下是类型错误:

Just 3 >>= \x -> x + 1
Run Code Online (Sandbox Code Playgroud)

具体来说,右侧需要返回一个Maybe Int,但它只返回一个Int.因此,我们可以使用return生成正确类型的值:

Just 3 >>= \x -> return (x + 1)
Run Code Online (Sandbox Code Playgroud)

但是,请考虑类似的表达方式.在以下情况中,使用return将是类型错误:

Just [("a", 1), ("b", 2)] >>= \l -> lookup "c"
Run Code Online (Sandbox Code Playgroud)

那是因为lookup函数的结果已经是一个Maybe Int值,所以使用return会产生一个Maybe (Maybe Int),这是错误的.

回到使用函数monad的示例,(n+)已经是类型的函数Int -> Int,因此使用return将是不正确的(它将生成类型的函数Int -> Int -> Int).但是,d + d它只是一个类型的值Int,因此您需要return将值提升到monad中.


值得注意的是,在这两种情况下,您总是可以替换return其底层实现.您可以使用Just而不是return在使用Maybemonad 时使用,而const不是return在使用monad函数时使用.但是,使用有两个很好的理由return:

  1. 使用return允许您编写与多种monad一起使用的函数.也就是说,return让你获得多态性.

  2. 使用return将普通值提升为monadic类型是非常惯用的,所以它总是看起来更清晰,噪音更小,return而不是看到许多不同名称的不同函数.