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