【问题标题】:Create a type that is a subset of an other type创建一个类型,它是其他类型的子集
【发布时间】:2020-04-08 06:16:33
【问题描述】:

如何创建属于其他类型子集的类型?我想要一个只包含字母数字字符的字符串类型。

所以我想要这样的东西

type AlphNumString = [AlphaNumChar]
data AlphaNumChar = ???? filter (isAlphaNum) Char ????

【问题讨论】:

  • filter 不是类型,而是函数
  • @MarkSeemann,没错,过滤器是一个函数,而不是一个类型。我希望引导的是一种在某些条件下从其他类型派生类型的方法。
  • @Henk 遗憾的是,Haskell 没有办法真正简单地 做到这一点。聪明的构造函数是你能做的最好的。 (作为一个愚蠢的例子,想象一个只包含素数的Int 子类型。编译器怎么知道素数是什么?显然这必须在用户代码中发生......)

标签: haskell types


【解决方案1】:

执行此操作的标准方法是使用所谓的“smart constructors”。

首先,您定义一个与旧类型相同的新类型:

newtype AlphNumString = X String

接下来,您自己编写智能构造函数:

toAlphNumString :: String -> AlphNumString
toAlphNumString txt = X (filter isAlphNum txt)

最后,你做到了,toAlphNumString唯一创建AlphNumString 的方法。

module Foo (AlphNumString (), toAlphNumString, ...) where ...

请注意,这允许您像普通的String 一样使用AlphNumString;你不能在 Haskell 中创建这样的“子类型”。所以你还需要另一个函数

fromAlphNumString :: AlphNumString -> String
fromAlphNumString (X txt) = txt

【讨论】:

  • 对于我正在处理的特定案例,我不介意这种限制。但是,我可以想象使用字符串函数会很有用的情况。有没有办法自动包装这些功能?像 IsString 类 (Data.String) 这样的东西会有帮助吗?
  • 特别是对于 strings,如果您打开 OverloadedStrings 扩展。而 all 这样做是自动包装文字字符串;它不会使类型相同,只是使输入文字更容易。
【解决方案2】:

这种基于某些谓词作为其他类型“子集”的类型概念称为细化类型。对于 Haskell,这被实现为 LiquidHaskell

但是,我认为这是一项正在进行的研究。在实践中,我会使用新类型和动态检查,正如 MathematicalOrchid 在他们的回答中所描述的那样。

【讨论】:

    【解决方案3】:

    在依赖类型语言(Haskell 还不是)中,您可以为此使用依赖对。

    data Sigma : (t : Type) -> (t -> Type) -> Type where
      MkSigma : (x : t) -> p x -> Sigma t p
    
    data IsAlphaNum : (c : Char) -> Type where
      MkIsAlphaNum : isAlphaNum c = True -> IsAlphaNum c
    

    那么Sigma Char IsAlphNum 将是表示字母数字字符的类型。该类型的每个元素都包含一个字符和该字符是字母数字的证明。

    【讨论】:

    猜你喜欢
    • 2011-10-15
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多