Haskell 如何不用Do符号书写
我在处理可组合故障,并设法编写了一个带有签名的函数Haskell 如何不用Do符号书写,haskell,monads,composition,Haskell,Monads,Composition,我在处理可组合故障,并设法编写了一个带有签名的函数 getPerson :: IO (Maybe Person) 如果某人: data Person = Person String Int deriving Show 它是有效的,我用do符号写了它,如下所示: import Control.Applicative getPerson = do name <- getLine -- step 1 age <- getInt -- step 2 retu
getPerson :: IO (Maybe Person)
如果某人:
data Person = Person String Int deriving Show
它是有效的,我用do符号写了它,如下所示:
import Control.Applicative
getPerson = do
name <- getLine -- step 1
age <- getInt -- step 2
return $ Just Person <*> Just name <*> age
导入控件。应用程序
getPerson=do
name>=)和()以及编写失败和成功(不要用难以辨认的一行代码来迷惑我的代码)
编辑:我想我应该澄清,“在没有do符号的情况下,我应该如何重写getPerson”,我对getInt函数的关心程度不到一半。do符号以这种方式将语法修改为(>>=):
getPerson = do
name <- getLine -- step 1
age <- getInt -- step 2
return $ Just Person <*> Just name <*> age
getPerson2 =
getLine >>=
( \name -> getInt >>=
( \age -> return $ Just Person <*> Just name <*> age ))
变成
Person <$> Just name <*> age
这与您正在使用的类型相同,在IO
处实例化了m
变量。这意味着您可以编写:
getPerson3 :: MaybeT IO Person
getPerson3 = Person <$> lift getLine <*> getInt3
getInt3 :: MaybeT IO Int
getInt3 = MaybeT $ do
n <- fmap reads getLine :: IO [(Int,String)]
case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
这里的g
与f
做的事情完全相同,但是如果模式匹配失败怎么办
Prelude> f [Nothing]
[]
Prelude> g [Nothing]
*** Exception: <interactive>:1:17-34: Non-exhaustive patterns in lambda
现在我们有了
Prelude> g' [Nothing]
[]
fail
s有效性取决于monad。对于列表,它非常有用,基本上可以使模式匹配在列表理解中起作用。在Maybe
monad中也很好,因为模式匹配错误会导致计算失败,而Maybe
应该是Nothing
。对于IO
,可能没有那么多,因为它只是通过error
抛出一个用户错误异常
这就是全部内容。do
-表单的块var>=
如下e1>=\var->e2
。因此,您的getPerson
代码变成:
getPerson =
getLine >>= \name ->
getInt >>= \age ->
return $ Just Person <*> Just name <*> age
getPerson=
getLine>>=\name->
getInt>>=\age->
返回$Just Person Just name年龄
正如您所看到的,这与使用do
的代码没有太大区别实际上,根据
getPerson =
let f1 name =
let f2 age = return $ Just Person <*> Just name <*> age
f2 _ = fail "Invalid age"
in getInt >>= f2
f1 _ = fail "Invalid name"
in getLine >>= f1
getInt =
let f1 n = case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
f1 _ = fail "Invalid n"
in (fmap reads getLine :: IO [(Int,String)]) >>= f1
显然,这个翻译后的结果比lambda版本可读性差,但无论有无模式匹配,它都能工作。我知道do表示法是(>>=)的语法糖,但我从来没有见过确切的方法。这是有道理的,看起来像普通的lambda演算。至于你剩下的回答,再次谢谢你。”“人名年龄”显然更整洁,将来我可能会像这样“提升”纯粹的功能,不管提升意味着什么。这让我想到了你答案的第三部分,你介绍了mtl和monad变形金刚。我从来没有读过关于这些的书,也不知道关于它们的任何事情,因为我总是认为它们离我正在试验的东西更远。看来我下一步就要开始了。《真实世界》第18章Haskell()介绍了monad变形金刚。不幸的是,LYAH似乎没有涵盖他们。一般来说,提升意味着你把一些常规类型的东西放在一个更华丽的环境中。因此,使用
将纯函数提升为应用程序,单子变换器的提升
函数在底层单子中进行计算,并将其提升到奇特的组合单子中。左侧的东西有一个很小的注释:我将写人名年龄
为人名年龄
——它更清楚地描述了影响的位置(在age
)和where not(在Person name
)。@newacct:good point;我已经编辑以包含此信息。谢谢,我知道do notation被糖化了(>>=),但不确定具体是如何添加的。我一直在努力获得预期的(“我的”预期)ghci没有成功的结果。这看起来比人们使用嵌套paren时更令人愉快。另请参见:为了挑剔,请注意getPerson
不是一个函数,因为它的类型签名中没有->
;如果您想要比“value”更精确的名称,我会选择“IO action”。有关详细信息,请参见。
f :: Num b => [Maybe b] -> [b]
f x = do
Just n <- x
[n+1]
-- first attempt at desugaring f
g :: Num b => [Maybe b] -> [b]
g x = x >>= \(Just n) -> [n+1]
Prelude> f [Nothing]
[]
Prelude> g [Nothing]
*** Exception: <interactive>:1:17-34: Non-exhaustive patterns in lambda
g' :: Num b => [Maybe b] -> [b]
g' x = x >>= \x' -> case x' of
Just n -> [n+1]
_ -> fail "pattern match exception"
Prelude> g' [Nothing]
[]
getPerson =
getLine >>= \name ->
getInt >>= \age ->
return $ Just Person <*> Just name <*> age
getPerson =
let f1 name =
let f2 age = return $ Just Person <*> Just name <*> age
f2 _ = fail "Invalid age"
in getInt >>= f2
f1 _ = fail "Invalid name"
in getLine >>= f1
getInt =
let f1 n = case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
f1 _ = fail "Invalid n"
in (fmap reads getLine :: IO [(Int,String)]) >>= f1
f x = do
Just n <- x
[n+1]
f x =
let f1 Just n = [n+1]
f1 _ = fail "Not Just n"
in x >>= f1