haskell - few more monad - solving problem with Monads

本文介绍如何利用Haskell中的Monad来优雅地解决逆波兰表示法(RPN)问题,并通过函数组合实现更复杂的逻辑处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

We have seen the RPN can be solved with haskell in previous examples, now we will see how we can do use monad to solve it.

With monad,  you might not gain more in terms of just solving hte problem, but you will get more like logging ability or, graceful failure or somehting else. 

 

So, here is a example of how you can leverage the use of Monad to give more context information on the solution. 

 

import Data.List  
  
solveRPN :: String -> Double  
solveRPN = head . foldl foldingFunction [] . words  

 

 

as before this is what we have for the main body of the solution, 

 

 

foldingFunction :: [Double] -> String -> [Double]  
foldingFunction (x:y:ys) "*" = (x * y):ys  
foldingFunction (x:y:ys) "+" = (x + y):ys  
foldingFunction (x:y:ys) "-" = (y - x):ys  
foldingFunction xs numberString = read numberString:xs  

 

 now, we are looking to add graceful failure to the function, and we might change the signature to something like this: 

 

foldingFunction :: [Double] -> String -> Maybe [Double]  

 so we will return Just a new stack if success, otherwise we will return Nothing. 

 

we nees some assiisting functions.  like the readMaybe, 

 

readMaybe :: (Read a) => String -> Maybe a  
readMaybe st = case reads st of [(x,"")] -> Just x  
                                _ -> Nothing  

 

to test that with the interactive console.. 

ghci> readMaybe "1" :: Maybe Int  
Just 1  
ghci> readMaybe "GO TO HELL" :: Maybe Int  
Nothing  

 

so with that , readMaybe can return failure on some input that it is not valid. now, we can rewrite the code .. 

 

foldingFunction :: [Double] -> String -> Maybe [Double]  
foldingFunction (x:y:ys) "*" = return ((x * y):ys)  
foldingFunction (x:y:ys) "+" = return ((x + y):ys)  
foldingFunction (x:y:ys) "-" = return ((y - x):ys)  
foldingFunction xs numberString = liftM (:xs) (readMaybe numberString)  

 

and we will ignore those succeess cases and we will only show the failure case. here is what we might get for a invalid .. 

ghci> foldingFunction [] "1"  
Just [1.0]  
ghci> foldingFunction [] "1 wawawawa"  
Nothing  

 so with this, we will wrap it up and here is waht we can get .. 

import Data.List  
  
solveRPN :: String -> Maybe Double  
solveRPN st = do  
    [result] <- foldM foldingFunction [] (words st)  
    return result  

 so instead of normal foldl, we do a foldM,  so we will give  a shot...

ghci> solveRPN "1 2 * 4 +"  
Just 6.0  
ghci> solveRPN "1 2 * 4 + 5 *"  
Just 30.0  
ghci> solveRPN "1 2 * 4"  
Nothing  
ghci> solveRPN "1 8 wharglbllargh"  
Nothing  

 

 

Now that we have seen that we can solve some problems with monad , like the above we used that to solve the reverseRPN problem, now let's see how ew can compose monadic functions, 

 

first let's review some function composition. 

ghci> let f = (+1) . (*100)  
ghci> f 4  
401  
ghci> let g = (\x -> return (x+1)) <=< (\x -> return (x*100))  
ghci> Just 4 >>= g  
Just 401  

 

so you can see that instead of just . function composition, we use the >=> , but instead of id as the starting accumulator, and the . notatin, we uses "return" and "<=<" insteads. so 

 

ghci> let f = foldr (.) id [(+1),(*100),(+1)]  
ghci> f 1  
201  

 can be translated to somethng else. 

 

so let's divert to something else, rember that we have solved some problem like moveKnight questions. 

in3 start = return start >>= moveKnight >>= moveKnight >>= moveKnight   

 and we can check that if we can reach to some position in three moves 

canReachIn3 :: KnightPos -> KnightPos -> Bool  
canReachIn3 start end = end `elem` in3 start

 with monad, we can know not just three, but any numbers of moves, let's make it more general , here is the code. 

import Data.List  
  
inMany :: Int -> KnightPos -> [KnightPos]  
inMany x start = return start >>= foldr (<=<) return (replicate x moveKnight)  

 

as we know that we have return instead of "id".. 

and we can make it more general , here is what we will get.  

canReachIn :: Int -> KnightPos -> KnightPos -> Bool  
canReachIn x start end = end `elem` inMany x start  

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值