haskell - Haskell pattern matching inside of case
问题描述
I am trying to perform pattern matching inside of case clause:
-- 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)
)
The problem is with where pb in fb v = (Parser pb)
. How do I declare pb and then pattern match with call to (fb input').
Also the need for including the constructor Parser
in the declaration: data Parser a = Parser (String -> Maybe (a, String))
seems to complicate things a lot. It would have much simpler to write:
data Parser a = String -> Maybe (a, String)
, but that is not possible are there other ways to achieve this?
解决方案
您可以在任何允许使用这些表达式的地方使用let
或where
创建模式匹配:(缩短了一些行以使其适合 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
)
你没问的问题
你知道那Maybe
是一个Monad
吗?当您发现自己编写了很多额外的代码来传播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'
)
推荐阅读
- if-statement - 否则如果 - 谷歌脚本
- java - 每次线程变量发生变化时如何更新线程
- algorithm - 为什么递归树的时间复杂度等于叶节点数而不是节点总数?
- javascript - Javascript如何只获取元素的第一个数字
- docker - 自定义文件而不是 docker-compose.yml
- python - 在 macOS 上使用 Python 播放 MIDI 文件
- swift - 如何在 Swift 中使用自签名证书发送请求
- flutter - Flutter,在具有透明背景的图像背景-png上添加图像
- python-3.x - 如何在不同计算机上的 virtualenv 上无缝工作?
- swift - Swift过滤器映射减少哪个选项