"return"关键字有什么特别之处

Mak*_*see 12 monads haskell functional-programming

当我似乎理解Haskell的回归时,我尝试使用不同的替代方案,似乎返回不仅可以在monad链中的任何地方使用,而且可以完全排除

*Main> Just 9 >>= \y -> (Just y) >>= \x -> return x
Just 9

*Main> Just 9 >>= \y -> (return y) >>= \x -> (Just y)
Just 9

*Main> Just 9 >>= \y -> (Just y) >>= \x -> (Just x)
Just 9 
Run Code Online (Sandbox Code Playgroud)

即使我在自己的实例中省略了返回,我也只会收到警告......

data MaybeG a = NothingG | JustG a deriving Show 
instance Monad MaybeG where  
    --    return x = JustG x  
        NothingG >>= f = NothingG  
        JustG x >>= f  = f x  
        fail _ = NothingG  

Monad.hs:3:10:
    Warning: No explicit method nor default method for `return'
    In the instance declaration for `Monad MaybeG'
Run Code Online (Sandbox Code Playgroud)

我仍然可以使用monad

*Main> JustG 9 >>= \y -> (JustG 11) >>= \x -> (JustG y)
JustG 9

*Main> JustG 9 >>= \y -> (NothingG) >>= \x -> (JustG y)
NothingG
Run Code Online (Sandbox Code Playgroud)

那么return关键字有什么特别之处呢?这是关于更复杂的情况,我不能省略它吗?或者因为这是做事的"正确"方式,即使它们可以以不同的方式完成?

更新: ..或另一种选择,我可以定义自己的monadic值构造函数

finallyMyLastStepG :: Int -> MaybeG Int
finallyMyLastStepG a = JustG a  
Run Code Online (Sandbox Code Playgroud)

并生成同一链的另一个变体(具有相同的结果)

*Main> JustG 9 >>= \y -> (JustG 11) >>= \x -> (finallyMyLastStepG y)
JustG 9
Run Code Online (Sandbox Code Playgroud)

Don*_*art 37

那么return关键字有什么特别之处呢?

首先,return不是 Haskell中的关键字.这是一个重载的功能.

其类型由下式给出:

class  Monad m  where
    -- | Sequentially compose two actions, passing any value produced
    -- by the first as an argument to the second.
    (>>=)       :: m a -> (a -> m b) -> m b

    -- | Inject a value into the monadic type.
    return      :: a -> m a
Run Code Online (Sandbox Code Playgroud)

所以你看到这return是一个赋值类型的函数a,返回一个新的类型值m a,其中m某个类型是一个实例Monad.这些类型包括:

  • 单子 []
  • 单子 I0
  • 单子 Maybe
  • 单子 STM
  • 单子 ((->) r)
  • 单子 (Either e)
  • 单子 (ST s)

还有更多."Monad"实例应符合以下法律:

> return a >>= k  ==  k a
> m >>= return  ==  m
> m >>= (\x -> k x >>= h)  ==  (m >>= k) >>= h
Run Code Online (Sandbox Code Playgroud)

函数的实现a -> m a很容易猜到.这是最常见的monad的定义:

列表:

 return x = [x]
Run Code Online (Sandbox Code Playgroud)

也许

 return x = Just x
Run Code Online (Sandbox Code Playgroud)

所以你看到这return是一个重载函数,它将一个值"提升"为一个monadic包装器.因此,您可以在任何可以使用其定义的地方使用它.例如

Prelude> 1 : return 2
[1,2]
Run Code Online (Sandbox Code Playgroud)

或在所述do概念(有用,当链接的表达式).

> do v <- return 7 ; return v :: Maybe Int
Just 7
Run Code Online (Sandbox Code Playgroud)

使用monadic的真正原因return是在一些monad中组合多个值:

Prelude> do x <- return 1 ; y <- return 2 ; return (x + y) :: Maybe Int
Just 3
Prelude> do x <- Nothing  ; y <- return 2 ; return y
Nothing
Run Code Online (Sandbox Code Playgroud)

在最后一个语句中,您会看到链条在给定monad达到零值后如何短路.在这种情况下Nothing.

简介:return是一个重载函数,它将值提升为monadic包装器.您需要提升值时使用它.它不是一个控制流关键字,因为它是命令式语言.

  • @Maksee与定义适用于任意monad的多态函数相同的代码.这对Haskell的库来说至关重要.人们无法定义像`mapM`或`sequence`这样的函数,它们适用于任意monad,没有`return` - 你只能为单个monad定义它们.如果没有这种普遍性,那么monad就没有意义了! (4认同)

Eri*_*ert 13

我怀疑你误解了"回归"在Haskell中的monad语境中意味着什么.return是一个函数,它接受一个a并返回一个"包装a" - 也就是monad最简单的实例.在其他语言中,它通常被称为Unit.这不是return你在C语言中看到的"控制流" .

所以在你的Maybemonad 示例中,我们将return定义为一个函数,它接受一个a并返回一个Maybe a:

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

它做了什么?如果你给它x,它会让你回来Just x:

return x = Just x
Run Code Online (Sandbox Code Playgroud)

现在,您可以return在需要该功能时使用速记,而不是写出来:

\x -> Just x
Run Code Online (Sandbox Code Playgroud)

这是return因为当你用do符号写出monad时,它看起来就像你用C语言做的那样.

  • `return`不是语法糖.这是一个功能.虽然是多态的. (12认同)
  • 从技术上讲,单独`Just`也是'(\ x-> Just x)`的合适替代品,因为`Just`是一个普通的函数.而且,看到Eric Lippert回答Haskell问题真是太棒了. (2认同)