【问题标题】:Type with two enum fields in Haskell在 Haskell 中输入两个枚举字段
【发布时间】:2020-12-09 05:49:43
【问题描述】:

我有一个表示方向的类型,它有一个轴和一个方向:

data Dir = DirX | DirY | DirZ | DirW deriving (Show, Eq)
data Sign = Pos | Neg deriving (Show, Eq)
newtype Direction = Direction (Dir, Sign) deriving (Show, Eq)

这看起来有点过于复杂了。我不需要 SignDir 是不同的类型,我只想将事物与它们的构造函数进行模式匹配。那么有没有更好的方法来定义这种类型?

所以我想做的是某种

data Direction = Direction (DirX | DirY | DirZ | DirW) (Pos | Neg) deriving (Show, Eq)

因为我做\(Direction _ s) -> if s == Pos then ... else ...之类的事情,但我从不在Direction之外使用DirSign

我想我不是第一个问这个问题的人,但我真的不知道如何用谷歌搜索这个问题。

【问题讨论】:

  • 好吧,我认为您不应该将其包装在 2 元组中,您可以使用 data Direction = Direction Dir Sign deriving (Show, Eq),但是,我并不真正理解问题所在。如果您希望类型是参数化的,您可以创建一个参数数据类型,例如data Direction dir sign = Direction dir sign deriving (Eq, Show),然后使用Direction Dir Sign 来指定特定于此的数据类型。
  • 我不明白为什么你不需要 SignDir 是不同的类型。一个有 4 个可能的值,另一个有 2 个。为什么它们应该是相同的类型呢?除此之外,使用不同的类型将防止方向和符号之间的混淆,例如错误地传递错误的值。我的意思是,您可以简单地使用 (Int, Int) 并避免超出范围的值,但这将非常脆弱,因为您会使无效值可表示。
  • @DEYTD:欢迎来到 Stack Overflow!我认为,如果您编辑问题以添加以下内容,这将有助于人们提供解决方案:1. 使用这些类型的现有代码的小示例,以及 2. 您希望能够编写的代码示例.就目前而言,您想做什么有点不清楚。
  • 我认为问题是希望有一种匿名类型。如果 Sign 的唯一目的是用作悬挂 Direction 中使用的构造函数的地方,那么希望您不必给它指定一个与 Direction 不同的命名类型是合情合理的。但它并不能真正经得起深入审查,因此 Haskell 没有这样的功能。
  • @chi 问题是SignDir 是一种具有有限可能值的类型,Direction 是。但我认为像我一样定义它会更方便一些,然后通过 8 个不同的构造函数。

标签: haskell types enums anonymous-types algebraic-data-types


【解决方案1】:

不,没有更好的方法。

...再说一次,就个人而言,我已经觉得这种方式非常好。所以也许这不是一个可怕的负担。

当然,有一些方法可以定义您可能仍然感兴趣的完全不同的类型。例如,我过去曾沿这些路线使用方向类型,效果很好:

data Direction = Direction { x, y, z, w :: Int }
aboutFace (Direction x y z w) = Direction (-x) (-y) (-z) (-w)
-- e is a traditional name from linear algebra for an axis-aligned unit vector
ex = Direction 1 0 0 0
ey = Direction 0 1 0 0
ez = Direction 0 0 1 0
ew = Direction 0 0 0 1

【讨论】:

    【解决方案2】:

    您可以使用模式同义词来匹配来自同构类型的值。将pattern 视为type 的术语级别等价物。 BoolSign 的现成替代品,尽管Dir 没有方便的 4 路求和类型;你可以改用Either Bool Bool

    {-# LANGUAGE PatternSynonyms #-}
    
    -- type Sign = Bool
    -- All two-value types are isomorphic to Bool.
    pattern Pos = True
    pattern Neg = False
    
    -- type Dir = Either Bool Bool
    -- All four-value types are isomorphic to Either Bool Bool
    pattern DirX = Left True
    pattern DirY = Left False
    pattern DirZ = Right True
    pattern DirW = Right False
    
    data Direction = Direction Bool (Either Bool Bool)
    

    实际的映射并不重要。例如,如果 Pos 映射到 FalseNegTrue,这将同样有效。重要的是映射是单射的。

    您可以使用模式来创造价值

    x = Direction Pos DirX
    

    模式匹配

    showDir :: Direction -> String
    showDir (Direction Pos DirX) = "+X"
    -- etc
    

    然后

    > showDir x
    "+X"
    

    不过,我不认为将 SignDir 定义为不同的类型是个问题。

    【讨论】:

    • 嗯,这在另一个方向上似乎过于复杂了。虽然,将Sign 定义为Bool 的同义词以及更好的构造函数名称的模式非常有趣,因为布尔值的内置函数。因此,尽管您对我最初的问题没有帮助,但这仍然很有帮助。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 2019-07-22
    • 1970-01-01
    • 2018-10-21
    • 2015-08-22
    • 2022-07-28
    • 1970-01-01
    相关资源
    最近更新 更多