想象一下,我有以下数据类型和类型类(带有适当的语言扩展):
data Zero=Zero
data Succ n = Succ n
class Countable t where
count :: t -> Int
instance Countable Zero where
count Zero = 0
instance (Countable n) => Countable (Succ n) where
count (Succ n) = 1 + count n
是否可以编写一个函数,从整数中为我提供正确类型类实例的实例?基本上,一个函数f
使得count (f n) = n
我的尝试是以下变体,但这在编译时给了我一些类型错误:
f::(Countable k)=> Int -> k
f 0 = Zero
f n = Succ $ f (n-1)
在寻找解决方案时,我经常讨论依赖类型,但我还没有能够将这些讨论映射到我的用例。
背景:因为我意识到这会得到很多“你为什么要这样做”类型的问题......
我目前正在使用该Data.HList
包来处理异构列表。在这个库中,我想构建一个函数shuffle
,当给定一个整数时n
,它会将n
列表的第 th 个元素移到末尾。
例如,如果我有l=1:"Hello":32:500
,我想shuffle 1 l
给1:32:500:"Hello"
。
我已经能够编写专门的函数shuffle0
来回答用例shuffle 0
:
shuffle0 ::(HAppend rest (HCons fst HNil) l')=>HCons fst rest -> l'
shuffle0 (HCons fst rest) = hAppend rest (HCons fst HNil)
我还编写了这个函数next
来“包装”一个函数,例如next (shuffle n) = shuffle (n+1)
:
next :: (forall l l'. l -> l') -> (forall e l l'.(HCons e l) -> (HCons e l'))
next f = \(HCons e l)-> HCons e $ (f l)
我觉得我的类型签名可能无济于事,即没有长度编码(这是可能出现问题的地方):
shuffle 0=shuffle0
shuffle n= next (shuffle (n-1))
GHC 抱怨无法推断出洗牌的类型。
这并不让我感到惊讶,因为该类型可能不是很有根据。
直觉上我觉得应该提到列表的长度。我可以通过 type 函数获得特定 HList 类型的长度HLength
,并通过一些精心选择的约束重写 shuffle 以使其合理(至少我认为)。
问题是我仍然需要获得我选择的长度的类型级别版本,以便我可以在调用中使用它。我什至不确定这是否可行,但我觉得我会有更好的机会。