确定数据类型实例的构造函数

问题描述

我已经将自己编码到一个角落了吗?我的数据类型接近程序的入口点

data Token = A String | B String deriving (Eq,Show,Read)

在图书馆模块中,我有

type Constructor token = String -> token

回到入口点,我有类似的东西

constructor :: Constructor Token
constructor = A
tokenA :: Token
tokenA = A "a"
tokenB :: Token
tokenB = B "b"

在入口点和库之间的中间位置,我想使用的是

tokenUsesConstructor :: Constructor token -> token -> Bool

,以便可以对A执行某些操作,而可以对B执行不同的操作。以下内容对c无效,因为参数不能重复:

tokenUsesConstructor constructor (constructor _) = True
tokenUsesConstructor constructor (_ _)           = False
-- use.hs:21:35: error: Parse error in pattern: constructor

,并且如错误所示(指示上述两行的第一行),问题比这更根本,正如

所示
tokenUsesConstructor constructor token =
    case token of
        constructor _ -> True
         _            -> False

会出现相同的错误(我认为前者只是后者的一个加糖版本)。如果我可以得到字符串,则可以进行构造和比较,但这实际上是关于匹配的相同问题。

是否可以在不进行模式匹配的情况下解构数据类型的实例?我不想在数据定义中添加更多内容或将其转换为记录类型。

(顺便说一句,我已经通过在构造函数中创建一个任意标记,显示了原始术语和构造的术语,然后比较了单词的开头来解决了这个问题,但这似乎是一种解决方法。)

解决方法

模式的构造器部分必须是静态的;它不能是变量。您也不能在模式(“非线性”模式)中多次使用相同的变量,也不能使用全局变量名称作为模式来尝试通过相等来匹配该事物;模式中的变量名称始终匹配任何内容,并通过该名称将其绑定到新的本地变量。

此外,函数是完全不透明的,无法进行比较。即使可以,这也不是正确的选择:Constructor token表示类型为String -> token any 函数,不一定是{{1}的构造函数之一}类型。

如果要动态执行此检查,则可以为令牌创建单独的标记类型,并与之进行比较:

Token

如果看来您的所有构造函数中的 all 只接受一个data Token = A String | B String deriving (Eq,Read,Show) data Constructor = ConstructorA | ConstructorB deriving (Eq,Show) tokenConstructor :: Token -> Constructor tokenConstructor A{} = ConstructorA tokenConstructor B{} = ConstructorB tokenUsesConstructor :: Constructor -> Token -> Bool tokenUsesConstructor c t = tokenConstructor t == c 参数,那么您可以使用一个小类型的代数(t + t = 2×t ):

String

或者,您可以让此函数接受谓词作为参数,然后测试很简单(并且甚至可能不需要单独的函数):

data Token = Token
  { tokenConstructor :: Constructor,tokenString :: String
  }
  deriving (Eq,Show)

tokenUsesConstructor c t = tokenConstructor t == c
isA :: Token -> Bool
isA A{} = True
isA _ = False

isB :: Token -> Bool
isB B{} = True
isB _ = False

type Predicate a = a -> Bool

matches :: Predicate token -> token -> Bool
matches p t = p t  -- matches = ($) = id

还有更多涉及的解决方案,例如可以静态地知道此“标签”的GADT或使事物通用的各种方式,但是我认为它们是否合适取决于您尚未使用的实际用例的细节。 t描述。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...