在 Haskell 的 monad 表达式中何时使用或不使用 'return'
When to use or not to use 'return' in Haskell's monad expression
我有一个函数 a,它 1) 计算 (argument+) argument
,以及 2) 将它加倍 ()。
a :: Int -> Int
a = (id >>= (\n -> (n+))) >>= (\d -> return (d + d))
在这个函数中,我应该使用return来防止错误。
但是在这个三重函数中,returns ((argument+) argument)+ argument)
将输入参数变成三倍。我无法使用 return.
triplex :: Int -> Int
triplex = (id >>= (\n -> (n+))) >>= (\d -> (d+))
从这些例子中,我猜 return
的简单规则是 1) 当我们使用 return 值时我们使用 return
,2) 我们不使用 return
当我们 return 部分函数时。但我不确定这是正确的理解。那么,Haskell中的return
背后是否有规则?
Haskell中的return
函数与命令式编程语言中的return
关键字关系不大——它只是一个具有普通类型签名的普通函数:
return :: Monad m => a -> m a
基本上,return
接受任何旧值并将其“提升”到 monad 中。当您将 m
替换为具体类型时,此函数的作用会更清楚一些,例如 Maybe
:
return :: a -> Maybe a
上面的函数只有一个实现,那就是Just
,所以return = Just
对于Maybe
monad。
在您的例子中,您使用的是函数 monad,(->) r
,通常也称为“reader”monad。执行与 Maybe
相同的替换,我们得到以下签名:
return :: a -> r -> a
这个函数也只有一个实现,即忽略它的第二个参数和return它的第一个。这就是 const
所做的,所以 return = const
用于函数。
“什么时候使用return
”的问题是有道理的,但是理解了上面的内容后应该更有意义:当值[=99=时需要使用return
]ed 从传递给 >>=
的函数不是单子的,因此需要“提升”。例如,以下将是类型错误:
Just 3 >>= \x -> x + 1
具体来说,右侧需要return一个Maybe Int
,但它只是return一个Int
。因此,我们可以使用 return
来生成正确类型的值:
Just 3 >>= \x -> return (x + 1)
但是,请考虑类似的表达式。在以下情况下,使用 return
会出现类型错误:
Just [("a", 1), ("b", 2)] >>= \l -> lookup "c"
那是因为lookup
函数的结果是已经一个Maybe Int
值,所以使用return
会产生一个Maybe (Maybe Int)
,这是错误的。
回到你使用函数 monad 的例子,(n+)
已经是一个 Int -> Int
类型的函数,所以使用 return
是不正确的(它会产生一个 Int -> Int
类型的函数=42=]).但是,d + d
只是一个 Int
类型的值,因此您需要 return
将值提升到 monad 中。
值得注意的是,在这两种情况下,您始终可以将 return
替换为其底层实现。在使用 Maybe
monad 时可以使用 Just
而不是 return
,在使用函数 monad 时可以使用 const
而不是 return
。但是,使用 return
有两个很好的理由:
使用 return
可以让您编写可用于多种 monad 的函数。也就是说,return
让你 多态性 .
使用 return
将普通值提升为 monadic 类型是非常惯用的,因此总是看到 return
而不是看到许多不同的函数更清晰,噪音更小不同的名字。
我有一个函数 a,它 1) 计算 (argument+) argument
,以及 2) 将它加倍 (
a :: Int -> Int
a = (id >>= (\n -> (n+))) >>= (\d -> return (d + d))
在这个函数中,我应该使用return来防止错误。
但是在这个三重函数中,returns ((argument+) argument)+ argument)
将输入参数变成三倍。我无法使用 return.
triplex :: Int -> Int
triplex = (id >>= (\n -> (n+))) >>= (\d -> (d+))
从这些例子中,我猜 return
的简单规则是 1) 当我们使用 return 值时我们使用 return
,2) 我们不使用 return
当我们 return 部分函数时。但我不确定这是正确的理解。那么,Haskell中的return
背后是否有规则?
Haskell中的return
函数与命令式编程语言中的return
关键字关系不大——它只是一个具有普通类型签名的普通函数:
return :: Monad m => a -> m a
基本上,return
接受任何旧值并将其“提升”到 monad 中。当您将 m
替换为具体类型时,此函数的作用会更清楚一些,例如 Maybe
:
return :: a -> Maybe a
上面的函数只有一个实现,那就是Just
,所以return = Just
对于Maybe
monad。
在您的例子中,您使用的是函数 monad,(->) r
,通常也称为“reader”monad。执行与 Maybe
相同的替换,我们得到以下签名:
return :: a -> r -> a
这个函数也只有一个实现,即忽略它的第二个参数和return它的第一个。这就是 const
所做的,所以 return = const
用于函数。
“什么时候使用return
”的问题是有道理的,但是理解了上面的内容后应该更有意义:当值[=99=时需要使用return
]ed 从传递给 >>=
的函数不是单子的,因此需要“提升”。例如,以下将是类型错误:
Just 3 >>= \x -> x + 1
具体来说,右侧需要return一个Maybe Int
,但它只是return一个Int
。因此,我们可以使用 return
来生成正确类型的值:
Just 3 >>= \x -> return (x + 1)
但是,请考虑类似的表达式。在以下情况下,使用 return
会出现类型错误:
Just [("a", 1), ("b", 2)] >>= \l -> lookup "c"
那是因为lookup
函数的结果是已经一个Maybe Int
值,所以使用return
会产生一个Maybe (Maybe Int)
,这是错误的。
回到你使用函数 monad 的例子,(n+)
已经是一个 Int -> Int
类型的函数,所以使用 return
是不正确的(它会产生一个 Int -> Int
类型的函数=42=]).但是,d + d
只是一个 Int
类型的值,因此您需要 return
将值提升到 monad 中。
值得注意的是,在这两种情况下,您始终可以将 return
替换为其底层实现。在使用 Maybe
monad 时可以使用 Just
而不是 return
,在使用函数 monad 时可以使用 const
而不是 return
。但是,使用 return
有两个很好的理由:
使用
return
可以让您编写可用于多种 monad 的函数。也就是说,return
让你 多态性 .使用
return
将普通值提升为 monadic 类型是非常惯用的,因此总是看到return
而不是看到许多不同的函数更清晰,噪音更小不同的名字。