你不能在这样的新类型中使用整数字面量。它们已经被占用,所以它不是有效的语法。
cdk 的回答给出了一个更实际的场景,但我想我会举一个例子来说明如何在 Haskell 中实现你的上一个例子。
如果我们打开一些更有趣的扩展,我们可以说服 GHC 制作一个具有给定有限数量值的类型。但是,我可能不建议在实际代码中实际这样做,因为 GHC 目前对这种依赖类型的编程没有最好的支持。此外,不幸的是,这些值没有好听的名字。据我所知,没有办法给它们起像1, 2, 3... 这样的好名字(编辑:实际上,我们可以对此稍作改进,参见第二个代码块)。
可能是这样的:
{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeOperators #-}
module Fin (Fin (..))
where
import GHC.TypeLits -- We get Nat from here as well as the type-level `<=` and `+`.
-- This is a type parameterized by another type. The type that parameterizes (`Nat`)
-- behaves like natural numbers at a type level. The `Nat -> *` is the "kind" of the type
-- `Fin`. A kind is like a type for types. To put it another way, a kind is to a type what
-- a type is to a value. In this case, the type `Nat` has kind `Nat`.
data Fin :: Nat -> * where
FZero :: Fin upperBound
FSucc :: (1 <= upperBound) => Fin upperBound -> Fin (upperBound + 1)
-- This is ok, because we are using the "fourth" value in a type with five values.
fifthValue :: Fin 5
fifthValue = FSucc (FSucc (FSucc FZero))
-- This doesn't compile, because it tries to make something of type
-- `Fin 2` using a "3rd value".
-- thirdValue :: Fin 2
-- thirdValue = FSucc (FSucc FZero)
--
-- The only inhabitants of `FiniteList 2` are `FZero` and `FSucc FZero`
请注意,要实际获取 Eq 和 Ord 之类的实例,您可能需要做更多棘手的事情(我什至不完全确定它是否可能。它可能需要新的类型级自然数定理证明他们正在使用 GHC 7.10)。
我可能应该指出的另一件事是Nat 中的类型被命名为1, 2, ...。这没关系,因为没有其他任何东西在类型级别(仅在值级别)使用这些名称。
编辑:
如果我们打开更多的扩展,我们可以获得一个版本,您可以(几乎)直接指定值的名称:
{-# LANGUAGE DataKinds, KindSignatures, GADTs, TypeOperators, PolyKinds, TypeFamilies, UndecidableInstances #-}
import Data.Type.Equality
import GHC.TypeLits
type family (||) (a :: Bool) (b :: Bool) :: Bool where
True || x = True
False || x = x
type family Elem (a :: k) (xs :: [k]) :: Bool where
Elem x (y ': ys) = (x == y) || Elem x ys
Elem x '[] = False
data NamedFin :: [k] -> * where
Val :: ((a `Elem` as) ~ True) => Proxy a -> NamedFin as
-- Countdown n makes a type level list of Nats.
-- So, for example, Countdown 3 is a shorthand for '[3, 2, 1]
type family Countdown (a :: Nat) :: [Nat] where
Countdown 0 = '[]
Countdown n = (n - 1) ': Countdown (n - 1)
data Proxy a = Proxy deriving Show
type Example = NamedFin (Countdown 5) -- This is the same as NamedFin '[5, 4, 3, 2, 1]
-- This compiles...
example :: Example
example = Val (Proxy :: Proxy 4)
-- ...but this doesn't
-- example2 :: Example
-- example2 = Val (Proxy :: Proxy 10)
虽然为 Eq 和 Ord 创建实例仍然存在问题。