背景
因此,您不能像使用 list 那样对映射进行模式匹配。
这是正确的。Data.Map.Map
是一种抽象数据类型,意味着它的表示是隐藏的。在 Haskell 中,这意味着它的构造函数不会被导出。你不能编写代码来检查内部的平衡二叉搜索树Map
(你也不想这样做)——你必须通过它的公共接口,使用模块的导出函数来创建、查询和操作Map
s。
模式同义词的存在是为了弥补 ADT 编程和方程左侧模式匹配的便捷语法之间的差距。您可以将一些智能模式定义为模块 API 的一部分,而不必将 ADT 的实现与这些模式耦合。
你的问题
您会收到该错误,因为从语法上讲,模式同义词的右侧必须是模式,而不是表达式。模式(通常)是应用于某些变量绑定器的值构造函数的名称- 也就是说,在定义中
getBar (Foo bar baz) = bar
和在左侧定义将在右侧范围内的变量bar
。baz
它们是新的绑定,而不是对可能存在于某个外部范围内的任何bar
或变量的引用。baz
因此,我认为除了语法错误(Map.empty
不是局部变量的有效名称,这就是您收到该错误的原因)之外,您还犯了一个合乎逻辑的错误-您将无法参考Map.empty
反正在那个位置。
修复
正如我在评论中所建议的,您可以通过使用明确的双向模式同义词来修补您的代码。这是一个简洁的功能,它可以让您根据模式同义词是用作模式(即在模式上下文中)还是用作值构造函数(即在表达式上下文中)来赋予模式同义词不同的含义。
pattern EmptyStore <- StoreEnv (Map.null -> True)
where EmptyStore = StoreEnv Map.empty
在第一行中,我定义了EmptyStore
用作模式时的含义。该Map.null -> True
语法称为视图模式——它的意思是“将函数Map.null
应用于这部分模式,并将其结果与True
”相匹配。所以当内部为空时EmptyStore
匹配a 。StoreEnv
Map
StoreEnv
第二行定义了EmptyStore
用作表达式时的作用。它说表达式EmptyStore
是表达式的同义词StoreEnv Map.empty
-“创建一个空Map
并将其包装在一个StoreEnv
”中。
未修复
但是,我认为模式同义词 APIMap
并没有真正意义。为了可用,您应该真正定义一套完整的模式,以便用户有办法解构任何类型的Map
. 空的情况很容易处理,因为只有一个空的Map
,但是在非空上进行模式匹配意味着什么Map
?Map
s 并不意味着要订购容器 - 没有像 with 那样的“第一和休息” []
,所以这没有意义:
pattern Cons k v rest <- {- what goes here? -}
where Cons k v rest = insert k v rest
您可能会尝试定义一个模式,当映射中存在特定键时匹配:
pattern Contains k v <- (lookup k -> Just v)
但这不是有效的 Haskell(当它应该被绑k
定时被引用)。即使你能想出一个聪明的方式来表达它,这样的一组模式也必然是不完整的,因为你不能为每个可能的键编写子句。
换句话说,我认为您不应该尝试为此数据类型定义模式同义词。坚持普通功能!