Mapping over Type Level Literals

I was playing around with Haar functions and realised I could encode the constraints in the types
{-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE ScopedTypeVariables #-}
import GHC.TypeLits import Data.Proxy
data Haar (a :: Nat) (b :: Nat) = Haar { unHaar :: Double -> Double }
haar :: forall n k . (KnownNat n, KnownNat k, (2 * k - 1 <=? 2^n - 1) ~ 'True) => Haar n (2 * k - 1) haar = Haar g where g t | (k' - 1) * 2 ** (-n') < t && t <= k' * 2 ** (-n') = 2 ** ((n' - 1) / 2) | k' * 2 ** (-n') < t && t <= (k' + 1) * 2 ** (-n') = -2 ** ((n' - 1) / 2) | otherwise = 0 where n' = fromIntegral (natVal (Proxy :: Proxy n)) k' = 2 * (fromIntegral (natVal (Proxy :: Proxy k))) - 1
So now I can do e.g.
*Main> unHaar (haar :: Haar 3 7) 0.05 0.0 *Main> unHaar (haar :: Haar 3 6) 0.05
<interactive>:359:9: Couldn't match type ‘2 * k0’ with ‘7’ The type variable ‘k0’ is ambiguous Expected type: 'True Actual type: ((2 * k0) - 1) <=? ((2 ^ 3) - 1) In the first argument of ‘unHaar’, namely ‘(haar :: Haar 3 6)’ In the expression: unHaar (haar :: Haar 3 6) 0.05 In an equation for ‘it’: it = unHaar (haar :: Haar 3 6) 0.05 *Main> unHaar (haar :: Haar 3 9) 0.05
<interactive>:360:9: Couldn't match type ‘'False’ with ‘'True’ Expected type: 'True Actual type: ((2 * 5) - 1) <=? ((2 ^ 3) - 1) In the first argument of ‘unHaar’, namely ‘(haar :: Haar 3 9)’ In the expression: unHaar (haar :: Haar 3 9) 0.05 In an equation for ‘it’: it = unHaar (haar :: Haar 3 9) 0.05 *Main>
So errors get rejected at compilation time as one would like and with moderately informative error messages. But now of course I would like to map over n and k but these are at the type level. Can this be done? I imagine unsafeCoerce would have to come into it somewhere. Dominic Steinitz dominic@steinitz.org http://idontgetoutmuch.wordpress.com

On Sep 11, 2014, at 8:58 AM, Dominic Steinitz
But now of course I would like to map over n and k but these are at the type level. Can this be done? I imagine unsafeCoerce would have to come into it somewhere.
Mapping at the type level is probably possible, but I don't see exactly what you mean -- there aren't any lists around to map with. If you make the example a little more concrete, I may be able to help. Richard

If I were not using type literals then I would do something like this but then errors would occur at runtime.
haarEtouffe :: Int -> Int -> Double -> Double haarEtouffe n k t | n <= 0 = error "n must be >= 1" | k `mod`2 == 0 = error "k must be odd" | k < 0 || k > 2^n - 1 = error "k must be >=0 and <= 2^n -1" | (k' - 1) * 2 ** (-n') < t && t <= k' * 2 ** (-n') = 2 ** ((n' - 1) / 2) | k' * 2 ** (-n') < t && t <= (k' + 1) * 2 ** (-n') = -2 ** ((n' - 1) / 2) | otherwise = 0 where k' = fromIntegral k n' = fromIntegral n
n :: Int n = 100
xss :: [[(Double, Double)]] xss = map (\(m, k) -> map (\i -> let x = fromIntegral i / fromIntegral n in (x, haarEtouffe m k x)) [0..n - 1]) [(1,1), (2,1), (2,3), (3,1), (3,3), (3,5), (3,7)]
Dominic Steinitz
dominic@steinitz.org
http://idontgetoutmuch.wordpress.com
On 11 Sep 2014, at 21:43, Richard Eisenberg
On Sep 11, 2014, at 8:58 AM, Dominic Steinitz
wrote: But now of course I would like to map over n and k but these are at the type level. Can this be done? I imagine unsafeCoerce would have to come into it somewhere.
Mapping at the type level is probably possible, but I don't see exactly what you mean -- there aren't any lists around to map with. If you make the example a little more concrete, I may be able to help.
Richard

(sorry, I think I wrote this to Dominic only originally) You mean something like this: http://hub.darcs.net/mjm/type-list/browse/src/Data/Type/List.hs ? I'll push this library to Hackage in a moment. Regards, Marcin

Maybe - do I need to write my own type level lists to use it? E.g.
data HList (xs :: [*]) where Nil :: HList '[] (:+:) :: x -> HList xs -> HList (x ': xs)
Dominic Steinitz
dominic@steinitz.org
http://idontgetoutmuch.wordpress.com
On 12 Sep 2014, at 16:13, Marcin Mrotek
(sorry, I think I wrote this to Dominic only originally)
You mean something like this: http://hub.darcs.net/mjm/type-list/browse/src/Data/Type/List.hs ? I'll push this library to Hackage in a moment.
Regards, Marcin

if you're going that route, the Hlist package has a lot of machinery!
https://hackage.haskell.org/package/HList
worth checking out
On Tue, Sep 16, 2014 at 12:26 PM, Dominic Steinitz
Maybe - do I need to write my own type level lists to use it? E.g.
data HList (xs :: [*]) where Nil :: HList '[] (:+:) :: x -> HList xs -> HList (x ': xs)
Dominic Steinitz dominic@steinitz.org http://idontgetoutmuch.wordpress.com
On 12 Sep 2014, at 16:13, Marcin Mrotek
wrote: (sorry, I think I wrote this to Dominic only originally)
You mean something like this: http://hub.darcs.net/mjm/type-list/browse/src/Data/Type/List.hs ? I'll push this library to Hackage in a moment.
Regards, Marcin
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Now I see that since you don't have a type list anywhere in the return type, you might try to use type classes: (works with GHC context stack set to at least one more than the value of N) ------- {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE PolyKinds #-} import GHC.TypeLits import Data.Proxy import Data.Singletons data Haar (a :: Nat) (b :: Nat) = Haar { unHaar :: Double -> Double } haar :: forall n k . (KnownNat n, KnownNat k, (2 * k - 1 <=? 2^n - 1) ~ 'True) => Haar n (2 * k - 1) haar = Haar g where g t | (k' - 1) * 2 ** (-n') < t && t <= k' * 2 ** (-n') = 2 ** ((n' - 1) / 2) | k' * 2 ** (-n') < t && t <= (k' + 1) * 2 ** (-n') = -2 ** ((n' - 1) / 2) | otherwise = 0 where n' = fromIntegral (natVal (Proxy :: Proxy n)) k' = 2 * (fromIntegral (natVal (Proxy :: Proxy k))) - 1 data Natural = Z | S Natural type family FromNat n where FromNat Z = 0 FromNat (S n) = 1 + (FromNat n) type family ToNat i where ToNat 0 = Z ToNat n = S (ToNat (n - 1)) class Upto n where upto :: sing n -> [Integer] instance Upto Z where upto _ = [] instance (KnownNat (FromNat n), Upto n) => Upto (S n) where upto _ = natVal (undefined :: sing (FromNat n)) : upto (undefined :: sing n) class MapHaar (n :: Nat) (xs :: [(Nat,Nat)]) where maphaar :: sing1 n -> sing2 xs -> [[(Double, Double)]] instance MapHaar n '[] where maphaar _ _ = [] instance (Upto (ToNat n), MapHaar n xs, b ~ (2 * k - 1), b <= 2^a - 1, KnownNat n, KnownNat k, KnownNat a) => MapHaar n ('(a,b) ': xs) where maphaar sn _ = h : t where l = map (\i -> fromIntegral i / fromIntegral (natVal sn)) $ upto (undefined :: sing (ToNat n)) h = map (\x -> (x, unHaar (haar :: Haar a b) x)) l t = maphaar sn (undefined :: sing xs) data instance Sing 100 = S100 foo = maphaar S100 (undefined :: sing '[ '(1,1), '(2,1), '(2,3), '(3,1), '(3,5), '(3,7)]) ----- Regards, Marcin
participants (4)
-
Carter Schonwald
-
Dominic Steinitz
-
Marcin Mrotek
-
Richard Eisenberg