【问题标题】:Two-level type hierarchy with Haskell使用 Haskell 的两级类型层次结构
【发布时间】:2020-03-28 11:36:57
【问题描述】:

我想在我的应用程序中为 4 种方向建模:右、左、上和下。但是,我希望能够有一个函数,该函数仅将水平变量用于变量,将垂直变量用于其他变量。

为了解决这个问题,我可以有两种类型:Horizo​​ntalDirection 和 VerticalDirection:

data HorizontalDirection = RightDir | LeftDir
data VerticalDirection = UpDir | DownDir

foo :: HorizontalDirection -> VerticalDirection -> String
foo hDir vDir = "This works" 

但是,我也希望能够拥有一个可以采用一种类型以及另一种类型的函数,如下所示:

bar :: Direction -> String
bar (HorizontalDirection _) = "Horizontal!"
bar (VerticalDirection _)   = "Vertical!"

但这不起作用,因为 Horizo​​ntalDirection 和 VerticalDirection 不是数据构造函数。

我知道我可以使用 Either 并使其工作,如下所示:

bar :: (Either HorizontalDirection VerticalDirection) -> String
bar (Left _) = "Horizontal!"
bar (Right _) = "Vertical!"

但是,我想知道我是否可以在没有 Either 类型的情况下做到这一点。

我也尝试过使用类型类:

data HorizontalDirection = RightDir | LeftDir
data VerticalDirection = UpDir | DownDir

class Direction a

instance Direction HorizontalDirection
instance Direction VerticalDirection

baz :: Direction d => d -> String
baz RightDir = "Horizontal"

但这给了我以下编译器错误:

Direction.hs:21:5: error:
    • Couldn't match expected type ‘d’
                  with actual type ‘HorizontalDirection’
      ‘d’ is a rigid type variable bound by
        the type signature for:
          baz :: forall d. Direction d => d -> String
        at Direction.hs:20:1-33
    • In the pattern: RightDir
      In an equation for ‘baz’: baz RightDir = "Horizontal"
    • Relevant bindings include
        baz :: d -> String (bound at Direction.hs:21:1)

我的思维方式在这里完全错误吗?还是我只是错过了什么?

【问题讨论】:

  • 我不知道你反对在这里使用Either 是什么。如果只是构造函数的名称,您可以随时创建自己的 sum 类型,例如 data Direction = Horizontal HorizontalDirection | Vertical VerticalDirection
  • 如果你喜欢冒险,你可以看看union types
  • @RobinZigmond,这不是问题。我只是觉得这是错误的,因为我总是将 Either 视为一种错误处理方式。

标签: haskell types functional-programming


【解决方案1】:

您可以声明一个具有更有意义名称的新数据类型,而不是使用Either

data Direction
  = Horizontal HorizontalDirection
  | Vertical   VerticalDirection

bar :: Direction -> String
bar (Horizontal _) = "Horizontal!"
bar (Vertical _) = "Vertical!"

【讨论】:

  • 谢谢!这正是我想要的!
【解决方案2】:

你已经很接近了,但是你需要在类中定义函数:

class Direction a where
    baz :: a -> String

instance Direction HorizontalDirection where
    baz _ = "Horizontal"

instance Direction VerticalDirection where
    baz _ = "Vertical"

但是请注意,Haskell 是静态类型的,并且类型在编译时是已知的。

【讨论】:

  • 感谢您的建议!但是,我认为@Li-yao Xia 的答案是一个,因为它不需要类型类。
猜你喜欢
  • 1970-01-01
  • 2011-03-25
  • 2020-08-30
  • 2014-07-23
  • 1970-01-01
  • 2016-09-14
  • 2013-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多