Imagine I have the following data types and type classes (with proper language extensions):
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
Would it be possible to write a function that gives me , from an Integer, an instance of the proper typeclass instance? Basically, a function f
so that count (f n) = n
My attempts have been variants of the following, this gives me some type errors at compile time though:
f::(Countable k)=> Int -> k
f 0 = Zero
f n = Succ $ f (n-1)
I've run into discussions on dependent types a lot while looking for a solution, but I have yet to be able to map those discussions to my use-case.
Context: Because I realise that this will get a lot of "why would you want to do this" type of questions...
I'm currently using the Data.HList
package to work with heterogeneous lists. In this library, I would like to build a function shuffle
which , when given an integer n
, would shift the n
th element of the list to the end.
For example, if I had l=1:"Hello":32:500
, I'd want shuffle 1 l
to give 1:32:500:"Hello"
.
I've been able to write the specialised function shuffle0
that would answer the usecase for shuffle 0
:
shuffle0 ::(HAppend rest (HCons fst HNil) l')=>HCons fst rest -> l'
shuffle0 (HCons fst rest) = hAppend rest (HCons fst HNil)
I've also written this function next
that would "wrap" a function , such that 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)
I feel like my type signature might not help, namely there isn't length encoding (which is where problems could appear):
shuffle 0=shuffle0
shuffle n= next (shuffle (n-1))
GHC complains about not being able to deduce the type of shuffle.
This doesn't really surprise me as the type is probably not very well founded.
Intuitively I feel like there should be a mention of the length of the lists. I can get the length of a specific HList type through the HLength
type function, and with some nicely chosen constraints rewrite shuffle so that it's sound (at least I think).
The problem is that I still need to get the type-level version of my chosen length, so that I can use it in my call. I'm not even sure if with that this can work but I feel I'll have a better chance.
f :: Int -> (forall k. (Countable k) => k -> r) -> r
. This works for some use cases, but can get complex. There may also be an approach using thereflection
package but I haven't used that myself. A perhaps less-well-founded approach involves abusing template haskell. – John LInt
value to a type, because values are purely runtime and types need to be known at compile time. – shang