"亚型"有自己的Show并可在其他模块中使用

时间:2017-01-21 22:26:45

标签: haskell types

我很确定我的问题源于我是Haskell的新手,并且完全不了解类型系统。

我将在类型主题

上使用Haskell的wiki中使用的示例

定义了以下类型

 data Suit = Club | Diamond | Heart | Spade

现在第一个问题是,我想为每个"子类型实现Show" (Club,Diamond,Heart,Spade)但这似乎不起作用,因为它是DataKinds。所以我把它分成了自己的类型。 (这些属性没有多大意义,但我将它们添加到更接近实际代码的位置)

data ClubType = ClubType {
  clubName :: String,
  icon :: String
} 
instance Show ClubType where
  show (ClubType cn i) = "name: " ++ cn ++ ", icon: " ++ i

在套装类型中使用它们

data Suit = Club ClubType 
          | Diamond DiamondType 
          | Heart HeartType 
          | Spade SpadeType

现在我想使用Suit和"子类型" (俱乐部,钻石,心脏,锹)在另一个module。我只导出Suit (..)

用法

import Module1 (Suit(..))

getSuit :: String -> Suit
getSuit "Club" = getClub
getSuit "Heart" = getHeart
...

getClub :: () -> Club

现在再次ClubHeartDiamondSpade无法使用,因为它们是DataKinds。我如何使用"子类型"?我需要导出所有类型吗?如果我这样做,它是否符合getSuit的返回类型?

(对不起,如果这个例子没有多大意义,但我希望你能按照我想要的结果)

感谢

1 个答案:

答案 0 :(得分:5)

是的,听起来你并不真正了解类型系统。我会尽力澄清我认为你出错的地方。在你的例子中

data Suit = Club | Diamond | Heart | Spade

只有一种类型,即SuitClubDiamond等根本不是类型,如果您将它们称为“子类型”,您将会感到困惑。它们的正确名称是构造函数,它们本质上是Suit类型的值

Club :: Suit
Diamond :: Suit
...

所以你无法真正为“每一个”实现一个Show实例,你只能以通常的方式为整个类型Show实现一个Suit实例。构造函数上的模式匹配:

instance Show Suit where
    show Club = "Clubs"
    show Diamond = "Diamonds"
    show Heart = "Heart"
    show Spade = "Spade"

这在类型show上定义了单个函数Suit -> String,同样没有“子类型”发生任何事情。我想知道这是否就是你想要的。

由于您提到了datakinds,因此在类型级别使用构造函数仍然不会使它们成为类型 - 它们仍然是类型Suit的值。在类型级别使用它们的一个示例是通过以下方式索引GADT:

data Card :: Suit -> * where
    QueenOfSpades :: Card Spade
    OtherCard :: Int -> Card s   -- we'd want to encode the suit s at the data
                                 -- level too using a singleton, out of scope
                                 -- for this post

但这是相当高级的东西,可能不是你想要的东西。

我希望这能澄清一些事情。