我正在尝试编写从字符串中提取数字的函数,例如:
"321 43 123 213" -> [321, 43, 123, 3212]
"dsa" -> Error
"123 da" -> Error
我想使用readEither和monadic方式(我尝试理解monads)。我的尝试:
import Text.Read
unit :: Either String [Int]
unit = Right []
extractInt :: String -> Either String [Int]
extractInt s = helper (words s) where
helper (h:t) = (bind readEither h) . (helper t)
helper [] = Right []
bind :: (String -> Either String Int) -> String -> (Either String [Int] -> Either String [Int])
bind f x z = bind' (f x) z where
bind' (Left s) _ = Left s
bind' (Right i) (Right l) = Right (l ++ [i])
bind' (Left s) _ = Left s
错误:
Couldn't match expected type `a0 -> Either String [Int]'
with actual type `Either a1 [t0]'
In the return type of a call of `Right'
Probable cause: `Right' is applied to too many arguments
In the expression: Right [1]
In an equation for `helper': helper [] = Right [1]
Failed, modules loaded: none.
答案 0 :(得分:2)
您可以使用mapM函数对单词进行单一映射:
RDD
如果任何一个readEither调用都返回Left,那么该函数也会这样做。那是你在找什么?
答案 1 :(得分:2)
如果你想">> ="你的助手功能应如下所示:
helper [] = Right []
helper (w:ws) = readEither w >>= \i -> fmap (i:) (helper ws)
说明:显然,对于一个空的单词列表,我们需要一个空的整数列表。对于非空列表,我们对第一个单词readEither
执行Either String Int
,这会给我们Right
。绑定(>> =)会将生成的整数传递给右侧的函数,但前提是结果为Left
如果是helper
这是帮助程序的总体结果
现在,(>> =)右侧的函数将Either String [Int]
应用于剩余的单词。如我们所知,这将导致Right
。然后,它会预先设置将{1}}结果中第一个单词转换为列表所产生的整数(如果有的话)。但是,如果helper
返回Left
值,则fmap
不会更改任何内容,因此这将是整体结果。
所以带有(>> =)的第二行大致扩展为以下代码:
case readEither w of
Left err -> Left err
Right int -> case helper ws of
Left err -> Left err
Right ints -> Right (int:ints)