我认为我的问题很容易从简单的代码中理解,但另一方面,我不确定答案!直观地说,我想做的是给定一个类型列表 [*] 和一些依赖类型 Foo,生成类型 [Foo *]。也就是说,我想将依赖类型“映射”到基本类型上。
首先,我正在使用以下扩展
{-# LANGUAGE TypeOperators,DataKinds,GADTs,TypeFamilies #-}
假设我们有一些依赖类型
class Distribution m where
type SampleSpace m :: *
它表征了某个概率分布的样本空间。如果我们想在潜在的异质值上定义产品分布,我们可能会写类似
data PDistribution (ms :: [*]) where
DNil :: PDistribution ('[])
(:*:) :: Distribution m => m -> (PDistribution ms) -> PDistribution (m ': ms)
并补充它
data PSampleSpace (m :: [*]) where
SSNil :: PSampleSpace ('[])
(:+:) :: Distribution m => SampleSpace m -> (PSampleSpace ms) -> PSampleSpace (m ': ms)
这样我们就可以定义
instance Distribution (PDistribution ms) where
type SampleSpace (PDistribution ms) = PSampleSpace ms
现在这一切都相当不错,除了 PSampleSpace 的类型会导致一些问题。特别是,如果我们想直接构造一个PSampleSpace,例如
ss = True :+: 3.0 :+: SNil
我们必须明确地给它一组生成它或遇到单态限制的分布。此外,由于两个分布当然可以共享一个 SampleSpace(Normals 和 Exponentials 都描述了 Doubles),因此选择一个分布来修复类型似乎很愚蠢。我真正想定义的是定义一个简单的异构列表
data HList (xs :: [*]) where
Nil :: HList ('[])
(:+:) :: x -> (HList xs) -> HList (x ': xs)
并写下类似的东西
instance Distribution (PDistribution (m ': ms)) where
type SampleSpace (PDistribution (m ': ms)) = HList (SampleSpace m ': mxs)
其中 mxs 已以某种方式转换为我想要的 SampleSpaces 列表。当然,这最后一段代码不起作用,我不知道如何修复它。干杯!
编辑
就像我所提出的解决方案的问题的一个可靠的例子一样,假设我有这个类
class Distribution m => Generative m where
generate :: m -> Rand (SampleSpace m)
即使它看起来应该输入检查,以下
instance Generative (HList '[]) where
generate Nil = return Nil
instance (Generative m, Generative (HList ms)) => Generative (HList (m ': ms)) where
generate (m :+: ms) = do
x <- generate m
(x :+:) <$> generate ms
才不是。GHC 抱怨它
Could not deduce (SampleSpace (HList xs) ~ HList (SampleSpaces xs))
现在我可以使用我的 PDistribution GADT 进行工作,因为我在子发行版上强制使用所需的类型类。
最终编辑
所以有几种方法可以解决这个问题。TypeList 是最通用的。在这一点上,我的问题得到了更多的回答。