想象一下,我有以下数据类型和类型类(具有适当的语言扩展名):
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
是否有可能编写一个函数,从Integer中为我提供正确的类型类实例的实例?基本上,函数f
使count (f n) = n
我的尝试是以下变体,但这在编译时给了我一些类型错误:
f::(Countable k)=> Int -> k
f 0 = Zero
f n = Succ $ f (n-1)
我在寻找解决方案时经常讨论依赖类型,但我还没有能够将这些讨论映射到我的用例。
背景:因为我意识到这将会得到很多“你为什么要这样做”这类问题......
我目前正在使用Data.HList
包来处理异构列表。在这个库中,我想构建一个函数shuffle
,当给定一个整数n
时,它会将列表的n
元素移到最后。
例如,如果我有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抱怨无法推断出洗牌的类型。
这并不让我感到惊讶,因为这种类型可能不是很有根据。
直觉上我觉得应该提一下列表的长度。我可以通过HLength
类型函数获取特定HList类型的长度,并使用一些精心选择的约束重写shuffle以使其声音(至少我认为)。
问题是我仍然需要获取所选长度的类型级别版本,以便我可以在通话中使用它。我甚至不确定这是否可行,但我觉得我有更好的机会。
答案 0 :(得分:6)
要回答您的初始问题,您不能将f
从Int
写入整数的类型级归纳表示,而不需要完整的依赖类型系统(Haskell没有)。但是,您在“上下文”中描述的问题在Haskell中不需要这样的函数。
我相信以下内容大致是您所寻找的:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, FunctionalDependencies, UndecidableInstances #-}
import Data.HList
data Z = Z
data S n = S n
class Nat t
instance Nat Z
instance Nat n => Nat (S n)
class (Nat n, HList l, HList l') => Shuffle n l l' | n l -> l' where
shuffle :: n -> l -> l'
instance Shuffle Z HNil HNil where
shuffle Z HNil = HNil
instance (HAppend xs (HCons x HNil) ys, HList xs, HList ys) => Shuffle Z (HCons x xs) ys where
shuffle Z (HCons x xs) = hAppend xs (HCons x HNil)
instance (Shuffle n xs ys) => Shuffle (S n) (HCons x xs) (HCons x ys) where
shuffle (S n) (HCons x xs) = HCons x (shuffle n xs)
e.g。
*Main> shuffle (S Z) (HCons 1 (HCons "Hello" (HCons 32 (HCons 500 HNil))))
HCons 1 (HCons 32 (HCons 500 (HCons "Hello" HNil)))
这个定义背后的一般技术是首先考虑如何编写非依赖类型的版本(例如,在这里,如何将元素混洗到列表的末尾),然后将其转换为类型级别(约束)版本。注意,shuffle
的递归结构完全由类型类实例中约束的递归结构镜像。
这是否解决了你想要做的事情?