如何写无标记 [英] How to write without Do notation

查看:84
本文介绍了如何写无标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


$ b

  getPerson :: IO(也许Person )

其中一个人是:

  data Person = Person String Int派生显示

如下所示:

  import Control.Applicative 

getPerson = do
name< - getLine - step 1
age< - getInt - 步骤2
return $ Just Person< *>只需要名称< *>年龄

其中

  getInt :: IO(Maybe Int)
getInt = do
n< - fmap读取getLine :: IO [(Int,String)]
b((x,):[]) - > return(Just x)
_ - > return Nothing

我写这个函数的目的是创建可组合的可能失败。尽管我对Maybe和IO以外的monad没有多少经验,但如果我的数据类型更复杂且字段更多,链接计算将不复杂。



我的问题是,如果没有标记,我将如何重写?因为我无法将名称或年龄等名称绑定到值,所以我不确定从哪里开始。



提问的原因仅仅是为了提高我对( >> =)和(*),并组成失败和成功(不要用难以辨认的单行程序来谜题)。

编辑:我想我应该澄清一下,我应该如何重写getPerson而不使用do not notation,我不关心getInt函数的一半。

解决方案

Do-notation desugars to(>> =)syntax in this way:

  getPerson = do 
name< - getLine - step 1
age< - getInt - 步骤2
return $ Just Person< * GT;只需要名称< *>年龄

getPerson2 =
getLine>> =
(\ name - > getInt>> =
(\age - > return )

每一行在第一个之后,do-notation被翻译成一个lambda,然后绑定到前一行。这是将值绑定到名称的完全机械过程。我不明白如何使用符号或不会影响组合性;这是严格的语法问题。



您的其他功能类似:

  getInt :: IO(Maybe Int)
getInt = do
n < - fmap读取getLine :: IO [(Int,String)]
case b
(( x,):[]) - > return(Just x)
_ - > return Nothing

getInt2 :: IO(Maybe Int)
getInt2 =
(fmap reads getLine :: IO [(Int,String)])>> =
\\\
- >
((x,):[]) - >的情况n return(Just x)
_ - >返回Nothing

您看起来朝向的方向有几点:$ b​​
$ b

使用 Control.Applicative 时,通常使用< $> 将纯粹的功能提升到monad中。在最后一行中有一个很好的机会:

  Just Person< *>只需要名称< *>年龄

成为

  Person< $>只需要名称< *>年龄

另外,您应该查看monad变形金刚。 mtl 软件包是最普遍的,因为它带有Haskell平台,但还有其他选项。 Monad变换器允许您创建一个新的Monad,并具有底层monads的组合行为。在这种情况下,您正在使用类型为 IO(也许a)的函数。 mtl(实际上是一个基础库,变换器)定义了

pre $ newtype MaybeT ma = MaybeT {runMaybeT :: m(也许a)}

这与您使用的类型相同, m IO 处实例化的变量。这意味着您可以编写:

  getPerson3 :: MaybeT IO Person 
getPerson3 = Person< $>举起getLine< *> getInt3

getInt3 :: MaybeT IO Int
getInt3 = MaybeT $ do
n< - fmap读取getLine :: IO [(Int,String)]
case n
((x,):[]) - > return(Just x)
_ - > return Nothing

getInt3 是完全一样的对于 MaybeT 构造函数。基本上,只要你有一个 m(也许a),你可以把它包装在 MaybeT 中来创建一个 MaybeT ma 。这可以获得更简单的组合性,正如您可以通过 getPerson3 的新定义所看到的那样。这个函数根本不用担心失败,因为它全部由MaybeT管道处理。剩下的一块是 getLine ,它只是 IO String 。这是通过函数 lift 来提升到MaybeT monad中的。
$ b 编辑
newacct的评论意味着我应该提供一个模式匹配的例子;这与一个重要的例外情况基本相同。考虑这个例子(列表monad是我们感兴趣的monad,也许就是模式匹配的地方):

  f :: Num b => [也许b]  - > [b] 
fx = do
只需n < - x
[n + 1]

- 首先尝试解除f
g :: Num b => [也许b] - > [b]
g x = x>> = \(Just n) - > [n + 1]

这里 g 确实与 f 完全一样,但是如果模式匹配失败了?

 前奏> f [无] 
[]

前奏> g [Nothing]
***例外:< interactive>:1:17-34:lambda中的非穷举模式

发生了什么事?这种特殊情况是Haskell中最大的疣(IMO)之一, Monad 类的失败方法的原因。在注释中,当模式匹配失败失败被调用时。实际翻译将更接近:

  g':: Num b => [也许b]  - > [b] 
g'x = x>> = \ x' - >案例x'的
只是n - > [n + 1]
_ - >失败模式匹配异常

现在我们有

 前奏> g'[Nothing] 
[]

失败的有用性取决于monad。对于列表来说,它非常有用,基本上使列表解析中的模式匹配工作成为可能。它在 Maybe monad中也很好,因为模式匹配错误会导致计算失败,这正是 Maybe 应该是 Nothing 。对于 IO ,可能不是那么多,因为它只是通过 error 引发用户错误异常。



这是完整的故事。


I was playing around with composable failures and managed to write a function with the signature

getPerson :: IO (Maybe Person)

where a Person is:

data Person = Person String Int deriving Show

It works and I've written it in the do-notation as follows:

import Control.Applicative

getPerson = do
    name <- getLine -- step 1
    age  <- getInt  -- step 2
    return $ Just Person <*> Just name <*> age 

where

getInt :: IO (Maybe Int)
getInt = do
    n <- fmap reads getLine :: IO [(Int,String)]
    case n of
        ((x,""):[])   -> return (Just x)
        _ -> return Nothing

I wrote this function with the intent of creating composable possible failures. Although I've little experience with monads other than Maybe and IO this seems like if I had a more complicated data type with many more fields, chaining computations wouldn't be complicated.

My question is how would I rewrite this without do-notation? Since I can't bind values to names like name or age I'm not really sure where to start.

The reason for asking is simply to improve my understanding of (>>=) and (<*>) and composing failures and successes (not to riddle my code with illegible one-liners).

Edit: I think I should clarify, "how should I rewrite getPerson without do-notation", I don't care about the getInt function half as much.

解决方案

Do-notation desugars to (>>=) syntax in this manner:

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 ))

each line in do-notation, after the first, is translated into a lambda which is then bound to the previous line. It's a completely mechanical process to bind values to names. I don't see how using do-notation or not would affect composability at all; it's strictly a matter of syntax.

Your other function is similar:

getInt :: IO (Maybe Int)
getInt = do
    n <- fmap reads getLine :: IO [(Int,String)]
    case n of
        ((x,""):[])   -> return (Just x)
        _ -> return Nothing

getInt2 :: IO (Maybe Int)
getInt2 =
    (fmap reads getLine :: IO [(Int,String)]) >>=
     \n -> case n of
        ((x,""):[])   -> return (Just x)
        _             -> return Nothing

A few pointers for the direction you seem to be headed:

When using Control.Applicative, it's often useful to use <$> to lift pure functions into the monad. There's a good opportunity for this in the last line:

Just Person <*> Just name <*> age

becomes

Person <$> Just name <*> age

Also, you should look into monad transformers. The mtl package is most widespread because it comes with the Haskell Platform, but there are other options. Monad transformers allow you to create a new monad with combined behavior of the underlying monads. In this case, you're using functions with the type IO (Maybe a). The mtl (actually a base library, transformers) defines

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

This is the same as the type you're using, with the m variable instantiated at IO. This means you can write:

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

getInt3 is exactly the same except for the MaybeT constructor. Basically, any time you have an m (Maybe a) you can wrap it in MaybeT to create a MaybeT m a. This gains simpler composability, as you can see by the new definition of getPerson3. That function doesn't worry about failure at all because it's all handled by the MaybeT plumbing. The one remaining piece is getLine, which is just an IO String. This is lifted into the MaybeT monad by the function lift.

Edit newacct's comment suggests that I should provide a pattern matching example as well; it's basically the same with one important exception. Consider this example (the list monad is the monad we're interested in, Maybe is just there for pattern matching):

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]

Here g does exactly the same thing as f, but what if the pattern match fails?

Prelude> f [Nothing]
[]

Prelude> g [Nothing]
*** Exception: <interactive>:1:17-34: Non-exhaustive patterns in lambda

What's going on? This particular case is the reason for one of the biggest warts (IMO) in Haskell, the Monad class's fail method. In do-notation, when a pattern match fails fail is called. An actual translation would be closer to:

g' :: Num b => [Maybe b] -> [b]
g' x = x >>= \x' -> case x' of
                      Just n -> [n+1]
                      _      -> fail "pattern match exception"

now we have

Prelude> g' [Nothing]
[]

fails usefulness depends on the monad. For lists, it's incredibly useful, basically making pattern matching work in list comprehensions. It's also very good in the Maybe monad, since a pattern match error would lead to a failed computation, which is exactly when Maybe should be Nothing. For IO, perhaps not so much, as it simply throws a user error exception via error.

That's the full story.

这篇关于如何写无标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆