11

我正在尝试为带有空地图的新类型创建模式同义词。

{-# Language PatternSynonyms #-}

import qualified Data.Map as Map

newtype StoreEnv = StoreEnv (Map.Map Int String)
   deriving (Eq, Show)

pattern EmptyStore :: StoreEnv
pattern EmptyStore = StoreEnv Map.empty

编译时出现错误提示“绑定位置中的限定名称:Map.empty”。我相信“Map.empty”应该属于我在 newtype 中声明的类型“Map.Map Int String”。

我的问题是是否有办法正确地为空地图设置别名。

我将不胜感激任何反馈。

4

1 回答 1

5

背景

因此,您不能像使用 list 那样对映射进行模式匹配。

这是正确的。Data.Map.Map是一种抽象数据类型,意味着它的表示是隐藏的。在 Haskell 中,这意味着它的构造函数不会被导出。你不能编写代码来检查内部的平衡二叉搜索树Map(你也不想这样做)——你必须通过它的公共接口,使用模块的导出函数来创建、查询和操作Maps。

模式同义词的存在是为了弥补 ADT 编程和方程左侧模式匹配的便捷语法之间的差距。您可以将一些智能模式定义为模块 API 的一部分,而不必将 ADT 的实现与这些模式耦合。

你的问题

您会收到该错误,因为从语法上讲,模式同义词的右侧必须是模式,而不是表达式。模式(通常)是应用于某些变量绑定器的值构造函数的名称- 也就是说,在定义中

getBar (Foo bar baz) = bar

和在左侧定义将在右侧范围内的变量barbaz它们是新的绑定,而不是对可能存在于某个外部范围内的任何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 。StoreEnvMapStoreEnv

第二行定义了EmptyStore用作表达式时的作用。它说表达式EmptyStore是表达式的同义词StoreEnv Map.empty-“创建一个空Map并将其包装在一个StoreEnv”中。

未修复

但是,我认为模式同义词 APIMap并没有真正意义。为了可用,您应该真正定义一套完整的模式,以便用户有办法解构任何类型的Map. 空的情况很容易处理,因为只有一个空的Map,但是在非空上进行模式匹配意味着什么MapMaps 并不意味着要订购容器 - 没有像 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定时被引用)。即使你能想出一个聪明的方式来表达它,这样的一组模式也必然是不完整的,因为你不能为每个可能的键编写子句。

换句话说,我认为您不应该尝试为此数据类型定义模式同义词。坚持普通功能!

于 2018-04-16T14:39:49.633 回答