【问题标题】:Pattern matching in case expressions/list comprehensions案例表达式/列表推导中的模式匹配
【发布时间】:2015-05-15 18:49:51
【问题描述】:

为什么以下在列表推导中进行模式匹配的尝试不起作用?

示例:同时替换术语数据类型中的原子。

数据类型:

data Term a 
    = Atom a
    | Compound (Term a) (Term a)
    deriving Show

原子的替换算法(如果有的话,选择第一个匹配的替换并忽略其余部分):

subs :: [(Term a, Term a)] -> Term a -> Term a
subs subList term = case term of 
    atom@(Atom x)       ->  let substitutions = 
                                [ s | s@(Atom x, _) <- subList ]
                            in  if null substitutions
                                then atom
                                else snd . head $ substitutions
    (Compound t1 t2)    -> Compound (subs subList t1) (subs subList t2)

一些测试数据:

subList = [((Atom 'a'), Compound (Atom 'b') (Atom 'c'))]
term1 = Atom 'a' 
term2 = Atom 'x' 

运行示例结果:

>: subs subList term1
Compound (Atom 'b') (Atom 'c')

这是期望的行为,并且

>: subs subList term2
Compound (Atom 'b') (Atom 'c')

不是。

Strangley 显式匹配有效:

subs'' :: [(Term Char, Term Char)] -> Term Char -> Term Char
subs'' subList term = case term of 
    atom@(Atom _)       ->  let substitutions = 
                            [ s | s@(Atom 'a', _) <- subList ]
                            in  if null substitutions
                                then atom
                                else snd . head $ substitutions
    (Compound t1 t2)    -> Compound (subs subList t1) (subs subList t2)

subs''' subList term = case term of 
     atom@(Atom _)       ->  let substitutions = 
                             [ s | s@(Atom 'x', _) <- subList ]
                             in  if null substitutions
                                 then atom
                                 else snd . head $ substitutions
     (Compound t1 t2)    -> Compound (subs subList t1) (subs subList t2)

将测试数据结果输入:

&gt;: subs'' subList term1&gt;: subs'' subList term2
Compound (Atom 'b') (Atom 'c')

&gt;: subs''' subList term1&gt;: subs''' subList term2
Atom 'x'

我错过了什么?

【问题讨论】:

  • 为避免将来陷入此错误,我建议使用 -Wall 打开 GHC 警告:这将指出 x 被绑定两次(内部 x遮住外层)。

标签: haskell pattern-matching list-comprehension


【解决方案1】:

Haskell 有线性模式,这意味着模式中不能有重复的变量。此外,内部表达式中的模式变量会隐藏外部变量,而不是建立相同变量的相等性。

你正在尝试做这样的事情:

charEq :: Char -> Char -> Bool
charEq c c = True
charEq _ _ = False

但由于重复变量,这是一个错误。如果我们将第二个 c 移动到一个内部表达式,它会编译,但它仍然不能按预期工作:

charEq :: Char -> Char -> Bool
charEq c d = case d of
  c -> True
  _ -> False

这里的内部c 只是一个隐藏外部c 的新变量,所以charEq 总是返回True

如果我们想检查是否相等,我们必须明确使用==

subs :: [(Term a, Term a)] -> Term a -> Term a
subs subList term = case term of 
    atom@(Atom x)       ->  let substitutions = 
                                [ s | s@(Atom x', _) <- subList, x == x' ]
                            in  if null substitutions
                                then atom
                                else snd . head $ substitutions
    (Compound t1 t2)    -> Compound (subs subList t1) (subs subList t2)

【讨论】:

  • 非常感谢...如果我理解正确的话,a 在任何情况下都必须是Eq 的一个实例?
  • @jules 是的。我们没有在模式中进行相等测试的原因之一是因为并非所有类型都是Eq 的实例。我想它仍然可以作为语法糖来实现,但没有人真正认为它值得这么麻烦。
猜你喜欢
  • 2018-10-30
  • 2015-04-27
  • 2012-04-24
  • 1970-01-01
  • 2020-04-29
  • 2019-05-02
  • 1970-01-01
  • 2011-12-03
  • 1970-01-01
相关资源
最近更新 更多