[LYAH, in For a Few Monads More显示此功能,
solveRPN :: String -> Maybe Double
solveRPN st = do
[result] <- foldM foldingFunction [] (words st)
return result
将模式匹配与do
表达式结合使用以确保从foldM
出来的单子包装单个列表]
为了真正理解do
表达式以及Monad
的本质,我一直在用>>=
和>>
而不是do
表达式重写那本书中的大多数示例Real World Haskell中也有人建议使用,但我不记得是哪一章。
关于上面的功能,我有点困惑。不使用do
表达式编写代码的最简洁方法是什么?我能想到的最好的是
solveRPN :: String -> Maybe Double
solveRPN s = foldM step [] (words s) >>= \x -> case x of
[y] -> Just y
_ -> Nothing
但是我希望有一种更干净的东西,因为这有两个原因,所以很吵:
case
表达式,看起来比if
-then
-else
更好。[This question与当前版本有关。
Haskell报表中指定的desugaring of do
notation实际上包括模式匹配,以便处理现在与do
类型类一起指定的fail
的模式匹配失败。它可以写为MonadFail
或功能。
case
因此在您的示例中,可能看起来像这样。
do {e} = e
do {e;stmts} = e >> do {stmts}
do {p <- e; stmts} = let ok p = do {stmts}
ok _ = fail "..."
in e >>= ok
do {let decls; stmts} = let decls in do {stmts}
(当然solveRPN :: String -> Maybe Double
solveRPN st = foldM foldingFunction [] (words st) >>= \ x -> case x of
[result] -> return result
_ -> fail "Pattern match failure in do expression at file:line:col"
只是fail message :: Maybe a
。]
您可以使用Nothing
使其更加简洁,以避免多余的变量。]>
LambdaCase
这是标准的减重法,但是如果您想进一步打高尔夫球,可以使用辅助功能。如果要允许非单个列表,则标准
{-# LANGUAGE LambdaCase #-} solveRPN :: String -> Maybe Double solveRPN st = foldM foldingFunction [] (words st) >>= \ case [result] -> return result _ -> fail "Pattern match failure in do expression at file:line:col"
有效。
listToMaybe :: [a] -> Maybe a
没有标准
import Data.Maybe (listToMaybe) solveRPN :: String -> Maybe Double solveRPN st = foldM foldingFunction [] (words st) >>= listToMaybe
,但您可以轻松编写一个。
singletonToMaybe
然后使用单子合成运算符
singletonToMaybe :: [a] -> Maybe a singletonToMaybe [x] = Just x singletonToMaybe _ = Nothing -- or: singletonToMaybe xs = guard (isSingleton xs) *> listToMaybe xs isSingleton = null . drop 1
或<=<
以无点样式编写该函数。
>=>