为什么`Just String`在Haskell中会出错

时间:2014-10-18 12:52:03

标签: haskell

在Haskell中学习参数化类型主题时,我有一个微不足道但又令人筋疲力尽的问题。这是我的问题:

看看这是Maybe的定义:

data Maybe a = Just a | Nothing

我们使用它:

Just "hello world"
Just 100

但为什么不能采用类型变量

例如:

Just String
Just Int

我知道这个问题很愚蠢,但我仍然无法弄清楚......

2 个答案:

答案 0 :(得分:6)

嗯,首先请注意,StringInt不是类型变量,而是类型(类型常量,如果可以的话)。但对于你的问题,这并不重要。

重要的是Haskells 类型语言值语言之间的命运。这些通常是分开的。 StringInt以及Maybe使用的是类型语言,"hello world"100以及JustNothing住在价值语言。每个人都对另一方一无所知。只有,编译器知道"值的描述属于该类型",但实际类型仅在编译时存在,并且值仅在运行时存在。

有两件事情有点令人困惑:

  • 允许使用类型和值语言存在的名称。最着名的是(),仅仅是同义词类型

    newtype Endo a = Endo { runEndo :: a -> a }
    

    但实际上这些是两个单独的实体:类型构造函数Endo :: *->*(参见下面的*个东西)和值构造函数Endo :: (a->a) -> Endo a。它们碰巧共享相同的名称,但是在完全不同的范围内 - 就像你同时声明addTwo x = x + 2greet x = "Hello "++x一样,x符号的两种用法都与每个符号无关其他

  • data语法似乎混合了类型和值。在其他任何地方,类型和值必须始终用::分隔,最常见的是签名

         "hello world" :: String
         100           :: Int
         Just          :: Int -> Maybe Int
            {-hence-}Just 100 :: Maybe Int
         Nothing       :: Maybe Int
    
    foo :: (Num a, Ord a) => a -> Maybe a  -- this really means `forall a . (Num a, Ord a) => a -> Maybe a
    foo n | n <= 0     = Nothing
          | otherwise  = Just $ n - 1
    

    如果启用data,确实可以使用该语法以更独特的方式定义-XGADTs

    data Maybe a where
      Just    :: a -> Maybe a
      Nothing :: Maybe a
    

    现在我们再次::作为值级别(左)和类型级别之间的明确区别。


你实际上可以再提一个级别:上面的声明也可以写成

data Maybe :: * -> * where
  Just    :: a -> Maybe a
  Nothing :: Maybe a

此处Maybe :: * -> *表示&#34; Maybe是类型级别的内容, kind * -> *&#34 ;,即需要类型*的类型级参数(例如Int)并返回另一种类型级别的类*(此处为Maybe Int)。种类与类型相同。

答案 1 :(得分:0)

您当然可以声明data Maybe a = Just String | Nothing,并且您可以声明data Maybe a = Just Int | Nothing,但一次只能声明其中一个。使用类型变量允许以何种方式声明构造值的内容类型随类型变量的值而变化。所以data Maybe a = Just a | Nothing告诉我们内容&#34;内部&#34; Just正好是传递给Maybe的类型。那样Maybe String意味着&#34;内部&#34; Just类型为StringMaybe Int表示&#34;内部&#34; Just的值为Int