Could not deduce (Dim n0) - haskell

I want to build a Hilbert matrix using the linear package and convert it to a list of lists. While this seems an easy task the type level constraints come into my way:
import Linear
import Linear.V
import Data.Vector qualified as V
-- | Outer (tensor) product of two vectors
outerWith :: (Functor f, Functor g, Num a) => (a -> a -> a) -> f a -> g a -> f (g a)
{-# INLINABLE outerWith #-}
outerWith f a b = fmap (\x -> fmap (f x) b) a
hilbertV :: forall a n. (Fractional a, Dim n) => Integer -> V n (V n a)
hilbertV n =
let v = V $ V.fromList $ fromIntegral <$> [1..n]
w = V $ V.fromList $ fromIntegral <$> [0..n-1]
in luInv $ outerWith (+) w v
listsFromM :: V n (V n a) -> [[a]]
listsFromM m = vToList (vToList <$> m)
vToList :: V n a -> [a]
vToList = V.toList . toVector
hilbertL :: forall a. (Fractional a) => Integer -> [[a]]
hilbertL n = listsFromM (hilbertV n)
When doing this the following error arises in the last line hilbertL n = listsFromM (hilbertV n):
bench/Solve.hs:28:26: error:
• Could not deduce (Dim n0) arising from a use of ‘hilbertV’
from the context: Fractional a
bound by the type signature for:
hilbertL :: forall a. Fractional a => Integer -> [[a]]
at bench/Solve.hs:27:1-56
The type variable ‘n0’ is ambiguous
These potential instances exist:
three instances involving out-of-scope types
instance GHC.TypeNats.KnownNat n => Dim n -- Defined in ‘Linear.V’
instance Data.Reflection.Reifies s Int =>
Dim (Linear.V.ReifiedDim s)
-- Defined in ‘Linear.V’
instance forall k (n :: k) a. Dim n => Dim (V n a)
-- Defined in ‘Linear.V’
• In the first argument of ‘listsFromM’, namely ‘(hilbertV n)’
In the expression: listsFromM (hilbertV n)
In an equation for ‘hilbertL’: hilbertL n = listsFromM (hilbertV n)
How can i get this to compile?

First, the type of HilbertV is unsafe. You shouldn't pass in an Integer size if size should be determined from the type! I think you want this:
{-# LANGUAGE TypeApplications, UnicodeSyntax #-}
hilbertV :: ∀ a n. (Fractional a, Dim n) => V n (V n a)
hilbertV = luInv $ outerWith (+) w v
where v = V $ V.fromList $ fromIntegral <$> [1..n]
w = V $ V.fromList $ fromIntegral <$> [0..n-1]
n = reflectDim #n []
(The [] just fills the proxy argument with the most concise way to generate a value-less functor input, since it is easier to pass in the type information with -XTypeApplications.)
In fact, I'd avoid even passing around n twice at all. Instead, why not factor out the marginal generation:
hilbertV :: ∀ a n. (Fractional a, Dim n) => V n (V n a)
hilbertV = luInv $ outerWith (+) w v
where v = fromIntegral <$> enumFinFrom 1
w = fromIntegral <$> enumFinFrom 0
enumFinFrom :: ∀ n a . (Enum a, Dim n) => a -> V n a
enumFinFrom ini = V . V.fromList $ take (reflectDim #n []) [ini..]
Now, for hilbertL the problem is that you have a dependent type size. The trick to deal with that are Rank2-quantified functions; linear offers reifyDim/reifyVector etc. for the purpose.
hilbertL :: ∀ a . Fractional a => Int -> [[a]]
hilbertL n = reifyDim n hilbertL'
where hilbertL' :: ∀ n p . Dim n => p n -> [[a]]
hilbertL' _ = listsFromM $ hilbertV #n
Alternatively, you could also change hilbertV to take a proxy argument for the size and then just hand that in. I've always found this a bit ugly, but it's actually more compact in this case:
hilbertV :: ∀ a n p . (Fractional a, Dim n) => p n -> V n (V n a)
hilbertV np = luInv $ outerWith (+) w v
where v = V $ V.fromList $ fromIntegral <$> [1..n]
w = V $ V.fromList $ fromIntegral <$> [0..n-1]
n = reflectDim np
hilbertL :: ∀ a . Fractional a => Int -> [[a]]
hilbertL n = reifyDim n (\np -> listsFromM $ hilbertV np)

Related

Undefined error on defined function

I'm trying to implement a function that multiplies polynomials (represented using lists -- 3x^2 + 5x + 2 = P [2,5,3]):
newtype Poly a = P [a]
plus :: Num a => Poly a -> Poly a -> Poly a
plus (P a) (P b) = P (map (\(y,z) -> z + y) (zipWithPadding 0 a b))
where
zipWithPadding :: (Num a) => a -> [a] -> [a] -> [(a, a)]
zipWithPadding e (aa: as) (bb: bs) = ((aa, bb): zipWithPadding e as bs)
zipWithPadding e [] bs = zip (repeat e) bs
zipWithPadding e as [] = zip as (repeat e)
times :: Num a => Poly a -> Poly a -> Poly a
times (P a) (P b) = sum $ multList 0 [] a b
where
multList :: Num a => Int -> [Poly a] -> [a] -> [a] -> [Poly a]
multList _ s [] _ = s
multList e s (aa:as) bs = multList (e + 1) (s ++ (multElement e aa bs)) as bs
multElement :: Num a => Int -> a -> [a] -> [Poly a]
multElement e aa bs = [P $ replicate e 0 ++ (map (*aa) bs)]
instance Num a => Num (Poly a) where
(+) = plus
(*) = times
negate = undefined
fromInteger = undefined
-- No meaningful definitions exist
abs = undefined
signum = undefined
When I tried to run however, I got an undefined error:
*HW04> times (P [1,2,2]) (P [1,2])
*** Exception: Prelude.undefined
I'm confused.
Clearly you are calling one of the undefined methods in the Num instance for Poly.
You can determine which one is being called by using these definitions:
negate = error "Poly negate undefined"
fromInteger = error "Poly fromInteger undefined"
abs = error "Poly abs undefined"
signum = error "Poly signum undefined"
Running your test expression yields:
Poly *** Exception: Poly fromInteger undefined
The problem is in your use of sum which is essentially defined as:
sum xs = foldl (+) 0 xs
It is therefore calling fromInteger 0. You can fix this with:
fromInteger x = P [ fromInteger x ]
Update
The reason fromInteger for Poly a needs to be defined this way is
because we need to construct a list of Num a values, and fromInteger x
is the way to create a Num a from the Integer value x.
A polynomial is not really a Num, although there is a ring monomorphism Num a => a -> Poly a.
Discard that Num instance and use foldl plus instead of sum.
I'm going to take the position that you should not define an instance of a class simply to hijack the class's functions. The minimal definition of a Num instance expects certain functions to be defined; explicitly assigning undefined to those names does not qualify as a definition. Consider that Haskell provides a specific operator (++) for list concatenation instead of simply overloading (+) with an instance like
instance Num [a] where
a + [] = a
[] + b = b
(a:as) + b = a:(as + b)
(*) = undefined
negate = undefined
-- etc
Instead, define a class that does provide the operations you want. In this case, you want a Ring, which is a type along with two operations, addition and multipication, that obey certain laws. (Put briefly, the operations act as you would expect given the integers as an example, except multiplication is not required to be commutative.)
In Haskell, we would define the class as
class Ring a where
rplus :: a -> a -> a -- addition
rmult :: a -> a -> a -- multiplication
rnegate :: a -> a -- negation
runit :: a -- multiplicative identity
rzero :: a -- additive identity, multiplicative zero
Any value with a valid Num instance forms a ring, although you need to define the instances separately.
instance Ring Integer where
rplus = (+)
rmult = (*)
rnegate = negate
rzero = 0
runit = 1
instance Ring Float
rplus = (+)
rmult = (*)
rnegate = negate
rzero = 0
runit = 1
-- etc
You can define an instance of Ring for polynomials, as long as the coefficients form a ring as well.
newtype Poly a = P [a]
instance Ring a => Ring (Poly a) where
-- Take care to handle polynomials with different degree
-- Note the use of rplus and rzero instead of (+) and 0
-- when dealing with coefficients
rplus (P a) (P b) = case (compare (length a) (length b)) of
LT -> rplus (P (rzero:a)) (P b)
EQ -> P $ zipWith rplus a b
GT -> rplus (P a) (P (rzero:b))
-- I leave a correct implementation of rmult as an exercise
-- for the reader.
rmult = ...
rnegate (P coeffs) = P $ map rnegate coeffs
rzero = P [0]
runit = P [1]

Why can't GHC deduce this type?

Consider the following code snippet (from http://lpaste.net/180651):
{-# LANGUAGE ScopedTypeVariables #-}
class Natural n
newtype V n a = V [a]
dim :: Natural n => V n a -> Int
dim = undefined -- defined in my actual code
bad_fromList :: Natural n => [a] -> V n a
bad_fromList l = if length l == dim v then v else undefined -- this is line 11
where v = V l
good_fromList :: forall n a. Natural n => [a] -> V n a
good_fromList l = if length l == dim v then v else undefined
where v = V l :: V n a
GHCI gives the following error message:
test.hs:11:33: error:
• Could not deduce (Natural n0) arising from a use of ‘dim’
from the context: Natural n
bound by the type signature for:
bad_fromList :: Natural n => [a] -> V n a
at test.hs:10:1-41
The type variable ‘n0’ is ambiguous
• In the second argument of ‘(==)’, namely ‘dim v’
In the expression: length l == dim v
In the expression: if length l == dim v then v else undefined
Why can't GHCI deduce the type?
Or, in the following code, pure' and good_f compile, while bad_f gives a similar error message. Why?
pure' :: Natural n => a -> V n a
pure' x = v
where v = V $ replicate (dim v) x
bad_f :: Natural n => [a] -> (V n a, Int)
bad_f xs = (v, dim v)
where v = V xs
good_f :: Natural n => a -> (V n a, Int)
good_f x = (v, dim v)
where v = V $ replicate (dim v) x
As user2407038 suggested, enabling -XMonoLocalBinds makes the code work.

No instance for (Num a) arising from a use of `sum' - Instance Num

this function works fine:
fromDigits :: [Int] -> Int
fromDigits n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: [Int] -> Int -> [Int]
f n x = if (x==length n) then []
else (10^x):f n (x+1)
But if i want to change the type signature from the function, it does not work:
fromDigits :: (Num a) => [a] -> a
fromDigits n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: (Num a) => [a] -> a -> [a]
f n x = if (x==length n) then []
else (10^x):f n (x+1)
Shouldn't this work too?
Almost, but not quite. The basic problem is that length has type [a]->Int. This will work:
fromDigits :: Num a => [a] -> a
fromDigits n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: Num b => [b] -> Int -> [b]
f n x = if (x==length n) then []
else (10^x):f n (x+1)
As Oleg Grenrus points out, one should always be careful to check if Int might overflow. It is in fact possible for this to happen if Int is 30, 31, or 32 bits, although it is relatively unlikely. However, if that is a concern, there is a way around it, using another function:
lengthIsExactly :: Integral n => n -> [a] -> Bool
lengthIsExactly = -- I'll let you figure this one out.
-- Remember: you can't use `length` here,
-- and `genericLength` is horribly inefficient,
-- and there's a completely different way.
You can make it easier to see how the types of fromDigits and f match up using a GHC extension. Enable the extension by adding
{-# LANGUAGE ScopedTypeVariables #-}
to the very top of your source file. Then you can write
fromDigits :: forall a . Num a => [a] -> a
fromDigits n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: [a] -> Int -> [a]
f n x = if (x==length n) then []
else (10^x):f n (x+1)
This way, it's clear that the list arguments all have the same type.
The problem is that you are using other functions that require even more of type a than just Num a
(^) requires "Integral a"
This works
fromDigits' :: (Num a, Integral a)=>[a] -> a
fromDigits' n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: (Num a, Integral a)=>[a] -> a -> [a]
f n x = if (x==fromIntegral (length n)) then []
else (10^x):f n (x+1)

How do I build a list with a dependently-typed length?

Dipping my toe into the waters of dependent types, I had a crack at the canonical "list with statically-typed length" example.
{-# LANGUAGE DataKinds, GADTs, KindSignatures #-}
-- a kind declaration
data Nat = Z | S Nat
data SafeList :: (Nat -> * -> *) where
Nil :: SafeList Z a
Cons :: a -> SafeList n a -> SafeList (S n) a
-- the type signature ensures that the input list has at least one element
safeHead :: SafeList (S n) a -> a
safeHead (Cons x xs) = x
This seems to work:
ghci> :t Cons 5 (Cons 3 Nil)
Cons 5 (Cons 3 Nil) :: Num a => SafeList ('S ('S 'Z)) a
ghci> safeHead (Cons 'x' (Cons 'c' Nil))
'x'
ghci> safeHead Nil
Couldn't match type 'Z with 'S n0
Expected type: SafeList ('S n0) a0
Actual type: SafeList 'Z a0
In the first argument of `safeHead', namely `Nil'
In the expression: safeHead Nil
In an equation for `it': it = safeHead Nil
However, in order for this data-type to be actually useful, I should be able to build it from run-time data for which you don't know the length at compile time. My naïve attempt:
fromList :: [a] -> SafeList n a
fromList = foldr Cons Nil
This fails to compile, with the type error:
Couldn't match type 'Z with 'S n
Expected type: a -> SafeList n a -> SafeList n a
Actual type: a -> SafeList n a -> SafeList ('S n) a
In the first argument of `foldr', namely `Cons'
In the expression: foldr Cons Nil
In an equation for `fromList': fromList = foldr Cons Nil
I understand why this is happening: the return type of Cons is different for each iteration of the fold - that's the whole point! But I can't see a way around it, probably because I've not read deeply enough into the subject. (I can't imagine all this effort is being put into a type system that is impossible to use in practice!)
So: How can I build this sort of dependently-typed data from 'normal' simply-typed data?
Following #luqui's advice I was able to make fromList compile:
data ASafeList a where
ASafeList :: SafeList n a -> ASafeList a
fromList :: [a] -> ASafeList a
fromList = foldr f (ASafeList Nil)
where f x (ASafeList xs) = ASafeList (Cons x xs)
Here's my attempt to unpack the ASafeList and use it:
getSafeHead :: [a] -> a
getSafeHead xs = case fromList xs of ASafeList ys -> safeHead ys
This causes another type error:
Couldn't match type `n' with 'S n0
`n' is a rigid type variable bound by
a pattern with constructor
ASafeList :: forall a (n :: Nat). SafeList n a -> ASafeList a,
in a case alternative
at SafeList.hs:33:22
Expected type: SafeList ('S n0) a
Actual type: SafeList n a
In the first argument of `safeHead', namely `ys'
In the expression: safeHead ys
In a case alternative: ASafeList ys -> safeHead ys
Again, intuitively it makes sense that this would fail to compile. I can call fromList with an empty list, so the compiler has no guarantee that I'll be able to call safeHead on the resulting SafeList. This lack of knowledge is roughly what the existential ASafeList captures.
Can this problem be solved? I feel like I might have walked down a logical dead-end.
Never throw anything away.
If you're going to take the trouble to crank along a list to make a length-indexed list (known in the literature as a "vector"), you may as well remember its length.
So, we have
data Nat = Z | S Nat
data Vec :: Nat -> * -> * where -- old habits die hard
VNil :: Vec Z a
VCons :: a -> Vec n a -> Vec (S n) a
but we can also give a run time representation to static lengths. Richard Eisenberg's "Singletons" package will do this for you, but the basic idea is to give a type of run time representations for static numbers.
data Natty :: Nat -> * where
Zy :: Natty Z
Sy :: Natty n -> Natty (S n)
Crucially, if we have a value of type Natty n, then we can interrogate that value to find out what n is.
Hasochists know that run time representability is often so boring that even a machine can manage it, so we hide it inside a type class
class NATTY (n :: Nat) where
natty :: Natty n
instance NATTY Z where
natty = Zy
instance NATTY n => NATTY (S n) where
natty = Sy natty
Now we can give a slightly more informative existential treatment of the length you get from your lists.
data LenList :: * -> * where
LenList :: NATTY n => Vec n a -> LenList a
lenList :: [a] -> LenList a
lenList [] = LenList VNil
lenList (x : xs) = case lenList xs of LenList ys -> LenList (VCons x ys)
You get the same code as the length-destroying version, but you can grab a run time representation of the length anytime you like, and you don't need to crawl along the vector to get it.
Of course, if you want the length to be a Nat, it's still a pain that you instead have a Natty n for some n.
It's a mistake to clutter one's pockets.
Edit I thought I'd add a little, to address the "safe head" usage issue.
First, let me add an unpacker for LenList which gives you the number in your hand.
unLenList :: LenList a -> (forall n. Natty n -> Vec n a -> t) -> t
unLenList (LenList xs) k = k natty xs
And now suppose I define
vhead :: Vec (S n) a -> a
vhead (VCons a _) = a
enforcing the safety property. If I have a run time representation of the length of a vector, I can look at it to see if vhead applies.
headOrBust :: LenList a -> Maybe a
headOrBust lla = unLenList lla $ \ n xs -> case n of
Zy -> Nothing
Sy _ -> Just (vhead xs)
So you look at one thing, and in doing so, learn about another.
In
fromList :: [a] -> SafeList n a
n is universally quantified -- i.e. this signature is claiming that we should be able to build a SafeList of any length from the list. Instead you want to quantify existentially, which can only be done by defining a new data type:
data ASafeList a where
ASafeList :: SafeList n a -> ASafeList a
Then your signature should be
fromList :: [a] -> ASafeList a
You can use it by pattern matching on ASafeList
useList :: ASafeList a -> ...
useList (ASafeList xs) = ...
and in the body, xs will be a SafeList n a type with an unknown (rigid) n. You will probably have to add more operations to use it in any nontrivial way.
If you want to use dependently typed functions on runtime data, then you need to ensure, that this data doesn't violate encoded in type signatures laws. It's easier to understand this by an example. Here is our setup:
data Nat = Z | S Nat
data Natty (n :: Nat) where
Zy :: Natty Z
Sy :: Natty n -> Natty (S n)
data Vec :: * -> Nat -> * where
VNil :: Vec a Z
VCons :: a -> Vec a n -> Vec a (S n)
We can write some simple functions on Vec:
vhead :: Vec a (S n) -> a
vhead (VCons x xs) = x
vtoList :: Vec a n -> [a]
vtoList VNil = []
vtoList (VCons x xs) = x : vtoList xs
vlength :: Vec a n -> Natty n
vlength VNil = Zy
vlength (VCons x xs) = Sy (vlength xs)
For writing the canonical example of the lookup function we need the concept of finite sets. They are usually defined as
data Fin :: Nat -> where
FZ :: Fin (S n)
FS :: Fin n -> Fin (S n)
Fin n represents all numbers less than n.
But just like there is a type level equivalent of Nats — Nattys, there is a type level equivalent of Fins. But now we can incorporate value level and type level Fins:
data Finny :: Nat -> Nat -> * where
FZ :: Finny (S n) Z
FS :: Finny n m -> Finny (S n) (S m)
The first Nat is an upper bound of a Finny. And the second Nat corresponds to an actual value of a Finny. I.e. it must be equal to toNatFinny i, where
toNatFinny :: Finny n m -> Nat
toNatFinny FZ = Z
toNatFinny (FS i) = S (toNatFinny i)
Defining the lookup function is now straightforward:
vlookup :: Finny n m -> Vec a n -> a
vlookup FZ (VCons x xs) = x
vlookup (FS i) (VCons x xs) = vlookup i xs
And some tests:
print $ vlookup FZ (VCons 1 (VCons 2 (VCons 3 VNil))) -- 1
print $ vlookup (FS FZ) (VCons 1 (VCons 2 (VCons 3 VNil))) -- 2
print $ vlookup (FS (FS (FS FZ))) (VCons 1 (VCons 2 (VCons 3 VNil))) -- compile-time error
That was simple, but what about the take function? It's not harder:
type Finny0 n = Finny (S n)
vtake :: Finny0 n m -> Vec a n -> Vec a m
vtake FZ _ = VNil
vtake (FS i) (VCons x xs) = VCons x (vtake i xs)
We need Finny0 instead of Finny, because lookup requires a Vec to be non-empty, so if there is a value of type Finny n m, then n = S n' for some n'. But vtake FZ VNil is perfectly valid, so we need to relax this restriction. So Finny0 n represents all numbers less or equal n.
But what about runtime data?
vfromList :: [a] -> (forall n. Vec a n -> b) -> b
vfromList [] f = f VNil
vfromList (x:xs) f = vfromList xs (f . VCons x)
I.e. "give me a list and a function, that accepts a Vec of arbitrary length, and I'll apply the latter to the former". vfromList xs returns a continuation (i.e. something of type (a -> r) -> r) modulo higher-rank types. Let's try it:
vmhead :: Vec a n -> Maybe a
vmhead VNil = Nothing
vmhead (VCons x xs) = Just x
main = do
print $ vfromList ([] :: [Int]) vmhead -- Nothing
print $ vfromList [1..5] vmhead -- Just 1
Works. But aren't we just repeat ourself? Why vmhead, when there is vhead already? Should we rewrite all safe functions in an unsafe way to make is possible to use them on runtime data? That would be silly.
All we need is to ensure, that all invariants hold. Let's try this principle on the vtake function:
fromIntFinny :: Int -> (forall n m. Finny n m -> b) -> b
fromIntFinny 0 f = f FZ
fromIntFinny n f = fromIntFinny (n - 1) (f . FS)
main = do
xs <- readLn :: IO [Int]
i <- read <$> getLine
putStrLn $
fromIntFinny i $ \i' ->
vfromList xs $ \xs' ->
undefined -- what's here?
fromIntFinny is just like vfromList. It's instructive to see, what the types are:
i' :: Finny n m
xs' :: Vec a p
But vtake has this type: Finny0 n m -> Vec a n -> Vec a m. So we need to coerce i', so that it would be of type Finny0 p m. And also toNatFinny i' must be equal to toNatFinny coerced_i'. But this coercion is not possible in general, since if S p < n, then there are elements in Finny n m, that are not in Finny (S p) m, since S p and n are upper bounds.
coerceFinnyBy :: Finny n m -> Natty p -> Maybe (Finny0 p m)
coerceFinnyBy FZ p = Just FZ
coerceFinnyBy (FS i) (Sy p) = fmap FS $ i `coerceFinnyBy` p
coerceFinnyBy _ _ = Nothing
That's why there is Maybe here.
main = do
xs <- readLn :: IO [Int]
i <- read <$> getLine
putStrLn $
fromIntFinny i $ \i' ->
vfromList xs $ \xs' ->
case i' `coerceFinnyBy` vlength xs' of
Nothing -> "What should I do with this input?"
Just i'' -> show $ vtoList $ vtake i'' xs'
In the Nothing case a number, that was read from the input, is bigger, than the length of a list. In the Just case a number is less or equal to the length of a list and coerced to the appropriate type, so vtake i'' xs' is well-typed.
This works, but we introduced the coerceFinnyBy function, that looks rather ad hoc. Decidable "less or equal" relation would be the appropriate alternative:
data (:<=) :: Nat -> Nat -> * where
Z_le_Z :: Z :<= m -- forall n, 0 <= n
S_le_S :: n :<= m -> S n :<= S m -- forall n m, n <= m -> S n <= S m
type n :< m = S n :<= m
(<=?) :: Natty n -> Natty m -> Either (m :< n) (n :<= m) -- forall n m, n <= m || m < n
Zy <=? m = Right Z_le_Z
Sy n <=? Zy = Left (S_le_S Z_le_Z)
Sy n <=? Sy m = either (Left . S_le_S) (Right . S_le_S) $ n <=? m
And a safe injecting function:
inject0Le :: Finny0 n p -> n :<= m -> Finny0 m p
inject0Le FZ _ = FZ
inject0Le (FS i) (S_le_S le) = FS (inject0Le i le)
I.e. if n is an upper bound for some number and n <= m, then m is an upper bound for this number too. And another one:
injectLe0 :: Finny n p -> n :<= m -> Finny0 m p
injectLe0 FZ (S_le_S le) = FZ
injectLe0 (FS i) (S_le_S le) = FS (injectLe0 i le)
The code now looks like this:
getUpperBound :: Finny n m -> Natty n
getUpperBound = undefined
main = do
xs <- readLn :: IO [Int]
i <- read <$> getLine
putStrLn $
fromIntFinny i $ \i' ->
vfromList xs $ \xs' ->
case getUpperBound i' <=? vlength xs' of
Left _ -> "What should I do with this input?"
Right le -> show $ vtoList $ vtake (injectLe0 i' le) xs'
It compiles, but what definition should getUpperBound have? Well, you can't define it. A n in Finny n m lives only at the type level, you can't extract it or get somehow. If we can't perform "downcast", we can perform "upcast":
fromIntNatty :: Int -> (forall n. Natty n -> b) -> b
fromIntNatty 0 f = f Zy
fromIntNatty n f = fromIntNatty (n - 1) (f . Sy)
fromNattyFinny0 :: Natty n -> (forall m. Finny0 n m -> b) -> b
fromNattyFinny0 Zy f = f FZ
fromNattyFinny0 (Sy n) f = fromNattyFinny0 n (f . FS)
For comparison:
fromIntFinny :: Int -> (forall n m. Finny n m -> b) -> b
fromIntFinny 0 f = f FZ
fromIntFinny n f = fromIntFinny (n - 1) (f . FS)
So a continuation in fromIntFinny is universally quantified over the n and m variables, while a continuation in fromNattyFinny0 is universally quantified over just m. And fromNattyFinny0 receives a Natty n instead of Int.
There is Finny0 n m instead of Finny n m, because FZ is an element of forall n m. Finny n m, while FZ is not necessarily an element of forall m. Finny n m for some n, specifically FZ is not an element of forall m. Finny 0 m (so this type is uninhabited).
After all, we can join fromIntNatty and fromNattyFinny0 together:
fromIntNattyFinny0 :: Int -> (forall n m. Natty n -> Finny0 n m -> b) -> b
fromIntNattyFinny0 n f = fromIntNatty n $ \n' -> fromNattyFinny0 n' (f n')
Achieving the same result, as in the #pigworker's answer:
unLenList :: LenList a -> (forall n. Natty n -> Vec n a -> t) -> t
unLenList (LenList xs) k = k natty xs
Some tests:
main = do
xs <- readLn :: IO [Int]
ns <- read <$> getLine
forM_ ns $ \n -> putStrLn $
fromIntNattyFinny0 n $ \n' i' ->
vfromList xs $ \xs' ->
case n' <=? vlength xs' of
Left _ -> "What should I do with this input?"
Right le -> show $ vtoList $ vtake (inject0Le i' le) xs'
for
[1,2,3,4,5,6]
[0,2,5,6,7,10]
returns
[]
[1,2]
[1,2,3,4,5]
[1,2,3,4,5,6]
What should I do with this input?
What should I do with this input?
The code: http://ideone.com/3GX0hd
EDIT
Well, you can't define it. A n in Finny n m lives only at the type
level, you can't extract it or get somehow.
That's not true. Having SingI n => Finny n m -> ..., we can get n as fromSing sing.

Applying a fixed-length-vector-function to the inital part of a longer fixed-length-vector

I have the following definition of fixed-length-vectors using ghcs extensions GADTs, TypeOperators and DataKinds:
data Vec n a where
T :: Vec VZero a
(:.) :: a -> Vec n a -> Vec (VSucc n) a
infixr 3 :.
data VNat = VZero | VSucc VNat -- ... promoting Kind VNat
type T1 = VSucc VZero
type T2 = VSucc T1
and the following defiition of a TypeOperator :+:
type family (n::VNat) :+ (m::VNat) :: VNat
type instance VZero :+ n = n
type instance VSucc n :+ m = VSucc (n :+ m)
For my whole intented library to make sense, I need to apply a fixed-length-vector-function of type (Vec n b)->(Vec m b) to the inial part of a longer vector Vec (n:+k) b. Let's call that function prefixApp. It should have type
prefixApp :: ((Vec n b)->(Vec m b)) -> (Vec (n:+k) b) -> (Vec (m:+k) b)
Here's an example application with the fixed-length-vector-function change2 defined like this:
change2 :: Vec T2 a -> Vec T2 a
change2 (x :. y :. T) = (y :. x :. T)
prefixApp should be able to apply change2 to the prefix of any vector of length >=2, e.g.
Vector> prefixApp change2 (1 :. 2 :. 3 :. 4:. T)
(2 :. 1 :. 3 :. 4 :. T)
Has anyone any idea how to implement prefixApp?
(The problem is, that a part of the type of the fixed-length-vector-function has to be used to grab the prefix of the right size...)
Edit:
Daniel Wagners (very clever!) solution seems to have worked with some release candidate of ghc 7.6 (not an official release!). IMHO it shouldnt work, however, for 2 reasons:
The type-declaration for prefixApp lacks an VNum m in the context (for prepend (f b) to typecheck correctly.
Even more problematic: ghc 7.4.2 does not assume the TypeOperator :+ to be injective in its first argument (nor the second, but thats not essential here), which leads to a type error: from the type-declaration, we know that vec must have type Vec (n:+k) a and the type-checker infers for the expression split vec on the right-hand side of the definition a type of Vec (n:+k0) a. But: the type-checker cannot infer that k ~ k0 (since there is no assurance that :+ is injective).
Does anyone know a solution to this second issue? How can I declare :+ to be injective in its first argument and/or how can I avoid running into this issue at all?
Here is a version where split is not in a type class. Here we build a singleton type for natural numbers (SN), which enables to pattern match on `n' in the definition of split'.
This extra argument can then be hidden by the use of a type class (ToSN).
The type Tag is used to manually specify the non-inferred arguments.
(this answer has been co-authored with Daniel Gustafsson)
Here is the code:
{-# LANGUAGE TypeFamilies, TypeOperators, DataKinds, GADTs, ScopedTypeVariables, FlexibleContexts #-}
module Vec where
data VNat = VZero | VSucc VNat -- ... promoting Kind VNat
data Vec n a where
T :: Vec VZero a
(:.) :: a -> Vec n a -> Vec (VSucc n) a·
infixr 3 :.
type T1 = VSucc VZero
type T2 = VSucc T1
data Tag (n::VNat) = Tag
data SN (n::VNat) where
Z :: SN VZero
S :: SN n -> SN (VSucc n)
class ToSN (n::VNat) where
toSN :: SN n
instance ToSN VZero where
toSN = Z
instance ToSN n => ToSN (VSucc n) where
toSN = S toSN
type family (n::VNat) :+ (m::VNat) :: VNat
type instance VZero :+ n = n
type instance VSucc n :+ m = VSucc (n :+ m)
split' :: SN n -> Tag m -> Vec (n :+ m) a -> (Vec n a, Vec m a)
split' Z _ xs = (T , xs)
split' (S n) _ (x :. xs) = let (as , bs) = split' n Tag xs in (x :. as , bs)
split :: ToSN n => Tag m -> Vec (n :+ m) a -> (Vec n a, Vec m a)
split = split' toSN
append :: Vec n a -> Vec m a -> Vec (n :+ m) a
append T ys = ys
append (x :. xs) ys = x :. append xs ys
prefixChange :: forall a m n k. ToSN n => (Vec n a -> Vec m a) -> Vec (n :+ k) a -> Vec (m :+ k) a
prefixChange f xs = let (as , bs) = split (Tag :: Tag k) xs in append (f as) bs
Make a class:
class VNum (n::VNat) where
split :: Vec (n:+m) a -> (Vec n a, Vec m a)
prepend :: Vec n a -> Vec m a -> Vec (n:+m) a
instance VNum VZero where
split v = (T, v)
prepend _ v = v
instance VNum n => VNum (VSucc n) where
split (x :. xs) = case split xs of (b, e) -> (x :. b, e)
prepend (x :. xs) v = x :. prepend xs v
prefixApp :: VNum n => (Vec n a -> Vec m a) -> (Vec (n:+k) a -> (Vec (m:+k) a))
prefixApp f vec = case split vec of (b, e) -> prepend (f b) e
If you can live with a slightly different type of prefixApp:
{-# LANGUAGE GADTs, TypeOperators, DataKinds, TypeFamilies #-}
import qualified Data.Foldable as F
data VNat = VZero | VSucc VNat -- ... promoting Kind VNat
type T1 = VSucc VZero
type T2 = VSucc T1
type T3 = VSucc T2
type family (n :: VNat) :+ (m :: VNat) :: VNat
type instance VZero :+ n = n
type instance VSucc n :+ m = VSucc (n :+ m)
type family (n :: VNat) :- (m :: VNat) :: VNat
type instance n :- VZero = n
type instance VSucc n :- VSucc m = n :- m
data Vec n a where
T :: Vec VZero a
(:.) :: a -> Vec n a -> Vec (VSucc n) a
infixr 3 :.
-- Just to define Show for Vec
instance F.Foldable (Vec n) where
foldr _ b T = b
foldr f b (a :. as) = a `f` F.foldr f b as
instance Show a => Show (Vec n a) where
show = show . F.foldr (:) []
class Splitable (n::VNat) where
split :: Vec k b -> (Vec n b, Vec (k:-n) b)
instance Splitable VZero where
split r = (T,r)
instance Splitable n => Splitable (VSucc n) where
split (x :. xs) =
let (xs' , rs) = split xs
in ((x :. xs') , rs)
append :: Vec n a -> Vec m a -> Vec (n:+m) a
append T r = r
append (l :. ls) r = l :. append ls r
prefixApp :: Splitable n => (Vec n b -> Vec m b) -> Vec k b -> Vec (m:+(k:-n)) b
prefixApp f v = let (v',rs) = split v in append (f v') rs
-- A test
inp :: Vec (T2 :+ T3) Int
inp = 1 :. 2 :. 3 :. 4:. 5 :. T
change2 :: Vec T2 a -> Vec T2 a
change2 (x :. y :. T) = (y :. x :. T)
test = prefixApp change2 inp -- -> [2,1,3,4,5]
In fact, your original signature can also be used (with augmented context):
prefixApp :: (Splitable n, (m :+ k) ~ (m :+ ((n :+ k) :- n))) =>
((Vec n b)->(Vec m b)) -> (Vec (n:+k) b) -> (Vec (m:+k) b)
prefixApp f v = let (v',rs) = split v in append (f v') rs
Works in 7.4.1
Upd: Just for fun, the solution in Agda:
data Nat : Set where
zero : Nat
succ : Nat -> Nat
_+_ : Nat -> Nat -> Nat
zero + r = r
succ n + r = succ (n + r)
data _*_ (A B : Set) : Set where
_,_ : A -> B -> A * B
data Vec (A : Set) : Nat -> Set where
[] : Vec A zero
_::_ : {n : Nat} -> A -> Vec A n -> Vec A (succ n)
split : {A : Set}{k n : Nat} -> Vec A (n + k) -> (Vec A n) * (Vec A k)
split {_} {_} {zero} v = ([] , v)
split {_} {_} {succ _} (h :: t) with split t
... | (l , r) = ((h :: l) , r)
append : {A : Set}{n m : Nat} -> Vec A n -> Vec A m -> Vec A (n + m)
append [] r = r
append (h :: t) r with append t r
... | tr = h :: tr
prefixApp : {A : Set}{n m k : Nat} -> (Vec A n -> Vec A m) -> Vec A (n + k) -> Vec A (m + k)
prefixApp f v with split v
... | (l , r) = append (f l) r

Resources