【问题标题】:Haskell pattern matching inside of case案例内部的 Haskell 模式匹配
【发布时间】:2019-01-13 00:57:33
【问题描述】:

我正在尝试在 case 子句中执行模式匹配:

-- different types of Parsers:
-- type Parser = String -> Maybe (String, String)
-- type Parser = String -> Maybe (Tree, String)
-- type Parser = String -> Maybe (Int, String)

-- can be generalized as:

data Parser a = Parser (String -> Maybe (a, String))

class Monad' m where
 result :: a -> m a
 bind :: m a -> (a -> m b) -> m b

instance Monad' Parser where
 result v = Parser (\input -> Just (v, input))
 bind (Parser fa) fb = Parser (\input ->
                                 case (fa input) of
                                  Nothing -> Nothing
                                  Just(v, input') -> pb input' where pb in fb v = (Parser pb)
                              )

问题在于where pb in fb v = (Parser pb)。如何声明 pb,然后通过调用 (fb input') 进行模式匹配。

还需要在声明中包含构造函数Parserdata Parser a = Parser (String -> Maybe (a, String)) 似乎使事情复杂化了很多。写起来会简单得多: data Parser a = String -> Maybe (a, String),但这是不可能的,还有其他方法可以实现吗?

【问题讨论】:

  • 一般版本是StateT
  • @xgrommx 试图自己做以了解 monad

标签: haskell pattern-matching


【解决方案1】:

您可以使用letwhere 在允许使用这些表达式的任何地方创建模式匹配:(缩短一些行以使其适合 StackOverflow 的格式)

instance Monad' Parser where
 result v = Parser (\input -> Just (v, input))
 bind (Parser fa) fb = 
   Parser (\input -> case (fa input) of
       Nothing -> Nothing
       Just(v, input') -> pb input'
         where (Parser pb) = fb v
   )

= 或 =

instance Monad' Parser where
 result v = Parser (\input -> Just (v, input))
 bind (Parser fa) fb = 
   Parser (\input -> case (fa input) of
       Nothing -> Nothing
       Just(v, input') ->
         let (Parser pb) = fb v
          in  pb input'
   )

Haskell 98 不允许类型同义词的实例声明。 GHC 宣传了一个允许这样做的语言扩展,但我的经验是它会导致更深的问题。

解决模式匹配需求的标准方法是创建一条记录并使用该字段剥离构造函数。约定好像是使用un++类型的名字。

data Parser a = Parser { unParser :: (String -> Maybe (a, String))}

-- N.B. unParser :: Parser a -> String -> Maybe (a, String)

instance Monad' Parser where
 result v = Parser (\input -> Just (v, input))
 bind (Parser fa) fb = 
   Parser (\input -> case (fa input) of
       Nothing -> Nothing
       Just(v, input') -> unParser (fb v) input
   )

你没有问的问题

你知道MaybeMonad 吗?当您发现自己编写了很多额外的代码来传播 Nothing -> Nothing 时,忽略失败并让 Monad(或 Applicative)实例成为您的朋友真是太好了。

instance Monad' Parser where
 result v = Parser (\input -> Just (v, input))
 bind (Parser fa) fb = 
   Parser (\input -> do -- This is in the Maybe Monad. 
                        -- If any step fails the result is Nothing
       (v, input') <- fa input
       unParser (fb v) input'
   )

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2013-09-13
  • 2017-02-25
  • 1970-01-01
  • 2020-09-19
  • 2013-11-28
  • 2012-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多