如何在Haskell中编写这个依赖类型的示例?

时间:2013-10-18 04:41:29

标签: haskell gadt dependent-type

假设我想用常数c,一元函数符号f和谓词P表示一阶语言的有限模型。我可以将载体表示为列表m,常量作为元素m,函数作为m的有序元素对列表(可以通过辅助函数ap应用),谓词作为{{m元素的列表1}}满足它:

-- Models (m, c, f, p) with element type a
type Model a = ([a], a, [(a,a)], [a])

-- helper function application, assumes function is total
ap :: Eq a => [(a,b)] -> a -> b
ap ((x',y'):ps) x = if x == x' then y' else ap ps x

然后我可以在模型上构建特定的模型和操作。细节对我的问题并不重要,只是类型(但我已经包含了定义,因此您可以看到类型约束的来源):

unitModel :: Model ()
unitModel = ([()], (), [((),())], [])

cyclicModel :: Int -> Model Int
cyclicModel n | n > 0 = ([0..n-1], 0, [(i, (i+1)`mod`n) | i<-[0..n-1]], [0])

-- cartesian product of models
productModel :: (Eq a, Eq b) => Model a -> Model b -> Model (a,b)
productModel (m1, c1, f1, p1) (m2, c2, f2, p2) = (m12, c12, f12, p12) where
  m12 = [(x1,x2) | x1 <- m1, x2 <- m2]
  c12 = (c1, c2)
  f12 = [(x12, (ap f1 (fst x12), ap f2 (snd x12))) | x12 <- m12]
  p12 = [x12 | x12 <- m12, elem (fst x12) p1 && elem (snd x12) p2]

-- powerset of model (using operations from Data.List)
powerModel :: (Eq a, Ord a) => Model a -> Model [a]
powerModel (m, c, f, p) = (ms, cs, fs, ps) where
  ms = subsequences (sort m) -- all subsets are "normalized"
  cs = [c]
  fs = [(xs, nub (sort (map (ap f) xs))) | xs <- ms] -- "renormalize" the image of f
  ps = [xs | xs <- ms, elem c xs]

现在,我想给所有这些模型命名:

data ModelName = UnitModel
               | CyclicModel Int
               | Product ModelName ModelName
               | Power ModelName
               deriving (Show, Eq)

最后,我想编写这段代码,将每个名称映射到它命名的模型:

model_of UnitModel = unitModel
model_of (CycleModel n) = cycleModel n
model_of (Product m1 m2) = productModel (model_of m1) (model_of m2)
model_of (Power m1) = powerModel (model_of m1)

在定义类型的意义上,我尝试了许多方法使其工作,以便我可以正确使用model_of的这个定义,包括使用幻像类型,GADT和类型系列 - 但是没有找到了办法。 (但话说回来,我是Haskell的相对新人。)能做到吗?我该怎么办?

1 个答案:

答案 0 :(得分:9)

通过对ModelName使用GADT,您可以将给定名称与结果模型的类型参数相关联。以下是进行model_of编译所需的内容:

{-# LANGUAGE GADTs #-}

data ModelName t where
    UnitModel   :: ModelName ()
    CyclicModel :: Int -> ModelName Int
    Product     :: (Eq a, Eq b) => ModelName a -> ModelName b -> ModelName (a, b)
    Power       :: (Ord a) => ModelName a -> ModelName [a]

model_of :: ModelName t -> Model t
model_of UnitModel       = unitModel
model_of (CyclicModel n) = cyclicModel n
model_of (Product m1 m2) = productModel (model_of m1) (model_of m2)
model_of (Power m1)      = powerModel (model_of m1)
编辑:正如您所注意到的,正常的deriving子句不适用于GADT,但事实证明StandaloneDeriving工作得很好。

{-# LANGUAGE StandaloneDeriving #-}

deriving instance Show (ModelName t)
deriving instance Eq (ModelName t)

但请注意,Eq实例在这种情况下有点无意义,因为type-class允许您只比较相同类型的值,但不同的构造函数实际上产生不同类型的值。因此,例如,以下甚至不进行类型检查:

UnitModel == CyclicModel

因为UnitModelCyclicModel分别有不同的类型(ModelName ()ModelName Int)。对于出于某种原因需要删除其他类型信息的情况,可以使用诸如

之类的包装器
data Some t where
    Some :: t a -> Some t

你可以得到例如手动Eq的{​​{1}}个实例:

Some ModelName