Is there a name for a recursion scheme that's like a catamorphism, but that allows peeking at the final result while it's still running? Here's a slighly contrived example:
toPercents :: Floating a => [a] -> [a]
toPercents xs = result
where
(total, result) = foldr go (0, []) xs
go x ~(t, r) = (x + t, 100*x/total:r)
{-
>>> toPercents [1,2,3]
[16.666666666666668,33.333333333333336,50.0]
-}
This example uses total at each step of the fold, even though its value isn't known until the end. (Obviously, this relies on laziness to work.)
Though this is not necessarily what you were looking for, we can encode the laziness trick with a hylomorphism:
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TemplateHaskell #-}
import Data.Functor.Foldable
import Data.Functor.Foldable.TH
data CappedList c a = Cap c | CCons a (CappedList c a)
deriving (Eq, Show, Ord, Functor, Foldable, Traversable)
makeBaseFunctor ''CappedList
-- The seq here has no counterpart in the implementation in the question.
-- It improves performance quite noticeably. Other seqs might be added for
-- some of the other "s", as well as for the percentage; the returns, however,
-- are diminishing.
toPercents :: Floating a => [a] -> [a]
toPercents = snd . hylo percAlg sumCal . (0,)
where
sumCal = \case
(s, []) -> CapF s
(s, a : as) -> s `seq` CConsF a (s + a, as)
percAlg = \case
CapF s -> (s, [])
CConsF a (s, as) -> (s, (a * 100 / s) : as)
This corresponds to the laziness trick because, thanks to hylo fusion, the intermediate CappedList never actually gets built, and toPercents consumes the input list in a single pass. The point of using CappedList is, as moonGoose puts it, placing the sum at the bottom of the (virtual) intermediate structure, so that the list rebuilding being done with percAlg can have access to it from the start.
(It is perhaps worth noting that, even though it is done in a single pass, it seems difficult to get nice-and-constant memory usage from this trick, be it with my version or with yours. Suggestions on this front are welcome.)
I don't think there's explicitly a scheme for allowing function 1 to peek at each step at the end result of function 2. It seems like a somewhat odd one to want though. I think that in the end, it's going to boil down to either 1) running function 2, then running function 1 with the known result of function 2 (ie. two passes, which I think is the only way to get constant memory in your example) or 2) running them side-by-side, creating a function thunk (or relying on laziness) to combine them at the end.
The lazy foldr version you gave of course translates naturally into a catamorphism. Here's the functionalized catamorphism version,
{-# LANGUAGE LambdaCase #-}
import Data.Functor.Foldable
toPercents :: Floating a => [a] -> [a]
toPercents = uncurry ($) . cata alg
where
alg = \case
Nil -> (const [], 0)
Cons x (f,s) -> (\t -> 100*x / t : f t, s + x)
It doesn't seem nice stylistically to have to hand-parallelize the two catamorphisms though, particularly as then it doesn't encode the fact that neither stepwise-relies on the other. Hoogle finds bicotraverse, but it's unnecessarily general, so let's write our algebra-parallelization operator (&&&&),
import Control.Arrow
(&&&&) :: Functor f => (f a -> c) -> (f b -> d) -> f (a,b) -> (c,d)
f1 &&&& f2 = (f1 . fmap fst &&& f2 . fmap snd)
toPercents' :: Floating a => [a] -> [a]
toPercents' = uncurry ($) . cata (algList &&&& algSum)
algSum :: (Num a) => ListF a a -> a
algSum = \case
Nil -> fromInteger 0
Cons x !s -> s + x
algList :: (Fractional a) => ListF a (a -> [a]) -> (a -> [a])
algList = \case
Nil -> const []
Cons x s -> (\t -> 100*x / t : s t)
Just crazy experiment. I think we can fuse smth.
Also fix = hylo (\(Cons f a) -> f a) (join Cons) and we can replace on fix
toPercents :: Floating a => [a] -> [a]
toPercents xs = result
where
(_, result) = hylo (\(Cons f a) -> f a) (join Cons) $ \(~(total, _)) ->
let
alg Nil = (0, [])
alg (Cons x (a, as)) = (x + a, 100 * x / total: as)
in
cata alg xs
Related
I am aware that the following question exists:
haskell - How to quickcheck applicative homomorphism property? - Stack Overflow
However, the introduction of the following PRAGMA
{-# LANGUAGE ScopedTypeVariables #-}
didn't solve my issue.
These are my definitions:
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Laws where
import Control.Applicative ((<$>), liftA3)
import Data.Monoid
import Test.QuickCheck
import Test.QuickCheck.Function
import Test.QuickCheck.Gen
data BinTree a = Empty | Node a (BinTree a) (BinTree a) deriving (Show, Eq)
instance Functor BinTree where
fmap _ Empty = Empty
fmap f (Node x hi hd) = Node (f x) (fmap f hi) (fmap f hd)
instance Applicative BinTree where
-- pure :: a -> BinTree a
pure x = Node x (pure x) (pure x)
-- <*> :: BinTree (a -> b) -> BinTree a -> BinTree b
_ <*> Empty = Empty -- L1,
Empty <*> t = Empty
(Node f l r) <*> (Node x l' r') = Node (f x) (l <*> l') (r <*> r')
instance (Arbitrary a) => Arbitrary (BinTree a) where
arbitrary = oneof [return Empty, -- oneof :: [Gen a] -> Gen a
liftA3 Node arbitrary arbitrary arbitrary]
-- Identity
apIdentityProp :: (Applicative f, Eq (f a)) => f a -> Bool
apIdentityProp v = (pure id <*> v) == v
-- pure f <*> pure x = pure (f x) -- Homomorphism
apHomomorphismProp :: forall f a b. (Applicative f, Eq (f b)) => Fun a b -> a -> Bool
apHomomorphismProp (apply -> g) x = (((pure g :: f (a -> b)) <*> (pure x :: f a)) :: f b) == (pure (g x) :: f b)
main :: IO ()
main = quickCheck (apHomomorphismProp :: Fun Int Int -> Int -> Bool)
How can I fix the following error ?
Could not deduce (Applicative f0)
from the context: (Applicative f, Eq (f b))
It would have been easier to analyse the problem if you had included the full error message, which mentions an ambiguous type variable. The thing that GHC is complaining about is that f does not appear anywhere in the type signature of apHomomorphismProp, except in the quantifier and constraints.
Why is that a problem? Well, it isn't a problem... but it used to be in older Haskell versions, because there was no way for the compiler to tell when you're using apHomomorphismProp what applicative it's supposed to test here. In fact this is still the case with the way you are using it: apHomomorphismProp :: Fun Int Int -> Int -> Bool does not mention BinTree in any way, so how is the compiler supposed to know that's what you mean? For all it knows, you could as well be asking for, say, the Maybe applicative to be tested here.
The solution, in modern Haskell, is -XTypeApplications, which just lets you explicitly say what a type variable should be instantiated with.
{-# LANGUAGE TypeApplications #-}
main = quickCheck (apHomomorphismProp #BinTree :: Fun Int Int -> Int -> Bool)
In fact I would recommend also using this syntax to clarify the Int types:
main = quickCheck $ apHomomorphismProp #BinTree #Int #Int
However, there was still the compiler error with apHomomorphismProp, which is all because prior to TypeApplications, a signature like the one you gave to apHomomorphismProp was useless. But this restriction is now obsolete†, and it can be disabled with -XAllowAmbiguousTypes:
{-# LANGUAGE ScopedTypeVariables, UnicodeSyntax, AllowAmbiguousTypes, TypeApplications #-}
apHomomorphismProp :: ∀ f a b. (Applicative f, Eq (f b)) => Fun a b -> a -> Bool
apHomomorphismProp (apply -> g) x = (pure #f g <*> pure x) == pure (g x)
Note that I only need to mention #f for one of the pures, the other ones are automatically constrained to the same applicative.
†It's arguable whether it's really obsolete. What's probably still true is that if a beginner gives their function an ambiguous type, it's more likely a mistake that should be caught right there and then, rather than something that's actually intended for use with -XTypeApplications. An unintentionally ambiguous type can cause quite confusing errors further down the line.
In Haskell if I want to repeatedly apply an endomorphism a -> a to a value of type a I can just use iterate.
What about a function that is not an endomorphisms, but generic enough to work correctly on its return type?
Consider for example Just :: a -> Maybe a; I can write
Just . Just . Just ...
as many times as I want. Is there a way to write this shortly with something like
iterate' 3 Just :: a -> Maybe (Maybe (Maybe a))
or do we need something like dependent types to do this?
It is possible with a minor tweak to the syntax you proposed: iterate' #3 Just instead of iterate' 3 Just.
This is because the result type depends on the number, so the number has to be a type literal, not a value literal. As you correctly note, doing this with arbitrary numbers would require dependent types[1], which Haskell doesn't have.
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE TypeFamilies, KindSignatures, DataKinds,
FlexibleInstances, UndecidableInstances, ScopedTypeVariables,
FunctionalDependencies, TypeApplications, RankNTypes, FlexibleContexts,
AllowAmbiguousTypes #-}
import qualified GHC.TypeLits as Lit
-- from type-natural
import Data.Type.Natural
import Data.Type.Natural.Builtin
class Iterate (n :: Nat) (f :: * -> *) (a :: *) (r :: *)
| n f a -> r
where
iterate_peano :: Sing n -> (forall b . b -> f b) -> a -> r
instance Iterate 'Z f a a where
iterate_peano SZ _ = id
instance Iterate n f (f a) r => Iterate ('S n) f a r where
iterate_peano (SS n) f x = iterate_peano n f (f x)
iterate'
:: forall (n :: Lit.Nat) f a r .
(Iterate (ToPeano n) f a r, SingI n)
=> (forall b . b -> f b) -> a -> r
iterate' f a = iterate_peano (sToPeano (sing :: Sing n)) f a
If you load this in ghci, you can say
*Main> :t iterate' #3 Just
iterate' #3 Just :: a -> Maybe (Maybe (Maybe a))
*Main> iterate' #3 Just True
Just (Just (Just True))
This code uses two different type-level naturals: the built-in Nat from GHC.TypeLits and the classic Peano numerals from Data.Type.Natural. The former are needed to provide the nice iterate' #3 syntax, the latter are needed to perform the recursion (which happens in the Iterate class). I used Data.Type.Natural.Builtin to convert from a literal to the corresponding Peano numeral.
[1] However, given a specific way to consume the iterated values (e.g. if you know in advance that you'll only want to show them), you probably could adapt this code to work even for dynamic values of n. There's nothing in the type of iterate' that requires a statically known Nat; the only challenge is to prove that the result of the iteration satisfies the constraints you need.
You can do it with template haskell, if you know the number at compile time (but unless the number is pretty large I don't think it's worth the hassle). If you don't know the number yet at compile time, you need to correctly model the return type, which we can do using a non-regular type:
data Iter f a = Iter0 a | IterS (Iter f (f a))
iterate' :: Int -> (forall x. x -> f x) -> a -> Iter f a
iterate' 0 f x = Iter0 x
iterate' n f x = IterS (iterate' (n-1) f (f x))
Iter is essentially a way of expressing the data type a | f a | f (f a) | f (f (f a)) | .... To use the result you need to recurse on Iter. Also the function has to be of the form a -> f a for some type constructor f, so you may need to do some newtype wrapping to get there. So... it's kind of a pain either way.
You can do this without Template Haskell or type-level Nats. The kind of variable-depth recursive type you are building actually fits perfectly into the model of a free monad. We can use the unfold function from the free package to build up a Free structure and short-circuit when our counter reaches 0.
-- This extension is enabled so we can have nice type annotations
{-# Language ScopedTypeVariables #-}
import Control.Monad.Free (Free)
import qualified Control.Monad.Free as Free
iterate' :: forall f a. Functor f => Int -> (a -> f a) -> a -> Free f a
iterate' counter0 f x0 = Free.unfold run (counter0, x0)
where
-- If counter is 0, short circuit with current result
-- Otherwise, continue computation with modified counter
run :: (Int, a) -> Either a (f (Int, a))
run (0 , x) = Left x
run (counter, x) = Right (countDown counter <$> f x)
countDown :: Int -> a -> (Int, a)
countDown counter x = (counter - 1, x)
Now, it's easy to create and digest these types of values for any Functor.
> iterate' 3 Just True
Free (Just (Free (Just (Free (Just (Pure True))))))
> let f i = if i == 1 then Left "abort" else Right (i+1)
> iterate' 0 f 0
Pure 0
> iterate' 1 f 0
Free (Right (Pure 1))
> iterate' 2 f 0
Free (Right (Free (Left "abort")))
If your Functor also happens to be a Monad, you can use retract to collapse the recursive structure.
> Free.retract (iterate' 3 Just True)
Just True
> Free.retract (iterate' 0 f 0)
Right 0
> Free.retract (iterate' 1 f 0)
Right 1
> Free.retract (iterate' 2 f 0)
Left "abort"
I suggest reading the docs for Control.Monad.Free so you can get an idea for how these structures are created/consumed.
(Just as an aside, a -> Maybe a is an endomorphism, but it's an endomorphism in the Kleisli category of Maybe.)
I'm trying to define liftN for Haskell. The value-level implementation in dynamically typed languages like JS is fairly straightforward, I'm just having trouble expressing it in Haskell.
After some trial and error, I arrived at the following, which typechecks (note the entire implementation of liftN is undefined):
{-# LANGUAGE FlexibleContexts, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
import Data.Proxy
import GHC.TypeLits
type family Fn x (y :: [*]) where
Fn x '[] = x
Fn x (y:ys) = x -> Fn y ys
type family Map (f :: * -> *) (x :: [*]) where
Map f '[] = '[]
Map f (x:xs) = (f x):(Map f xs)
type family LiftN (f :: * -> *) (x :: [*]) where
LiftN f (x:xs) = (Fn x xs) -> (Fn (f x) (Map f xs))
liftN :: Proxy x -> LiftN f x
liftN = undefined
This gives me the desired behavior in ghci:
*Main> :t liftN (Proxy :: Proxy '[a])
liftN (Proxy :: Proxy '[a]) :: a -> f a
*Main> :t liftN (Proxy :: Proxy '[a, b])
liftN (Proxy :: Proxy '[a, b]) :: (a -> b) -> f a -> f b
and so on.
The part I'm stumped on is how to actually implement it. I was figuring maybe the easiest way is to exchange the type level list for a type level number representing its length, use natVal to get the corresponding value level number, and then dispatch 1 to pure, 2 to map and n to (finally), the actual recursive implementation of liftN.
Unfortunately I can't even get the pure and map cases to typecheck. Here's what I added (note go is still undefined):
type family Length (x :: [*]) where
Length '[] = 0
Length (x:xs) = 1 + (Length xs)
liftN :: (KnownNat (Length x)) => Proxy x -> LiftN f x
liftN (Proxy :: Proxy x) = go (natVal (Proxy :: Proxy (Length x))) where
go = undefined
So far so good. But then:
liftN :: (Applicative f, KnownNat (Length x)) => Proxy x -> LiftN f x
liftN (Proxy :: Proxy x) = go (natVal (Proxy :: Proxy (Length x))) where
go 1 = pure
go 2 = fmap
go n = undefined
...disaster strikes:
Prelude> :l liftn.hs
[1 of 1] Compiling Main ( liftn.hs, interpreted )
liftn.hs:22:28: error:
* Couldn't match expected type `LiftN f x'
with actual type `(a0 -> b0) -> (a0 -> a0) -> a0 -> b0'
The type variables `a0', `b0' are ambiguous
* In the expression: go (natVal (Proxy :: Proxy (Length x)))
In an equation for `liftN':
liftN (Proxy :: Proxy x)
= go (natVal (Proxy :: Proxy (Length x)))
where
go 1 = pure
go 2 = fmap
go n = undefined
* Relevant bindings include
liftN :: Proxy x -> LiftN f x (bound at liftn.hs:22:1)
|
22 | liftN (Proxy :: Proxy x) = go (natVal (Proxy :: Proxy (Length x))) where
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
At this point it isn't clear to me what exactly is ambiguous or how to disambiguate it.
Is there a way to elegantly (or if not-so-elegantly, in a way that the inelegance is constrained to the function implementation) implement the body of liftN here?
There are two issues here:
You need more than just the natVal of a type-level number to ensure the whole function type checks: you also need a proof that the structure you're recursing on corresponds to the type-level number you're referring to. Integer on its own loses all of the type-level information.
Conversely, you need more runtime information than just the type: in Haskell, types have no runtime representation, so passing in a Proxy a is the same as passing in (). You need to get in runtime info somewhere.
Both of these problems can be addressed using singletons, or with classes:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
data Nat = Z | S Nat
type family AppFunc f (n :: Nat) arrows where
AppFunc f Z a = f a
AppFunc f (S n) (a -> b) = f a -> AppFunc f n b
type family CountArgs f where
CountArgs (a -> b) = S (CountArgs b)
CountArgs result = Z
class (CountArgs a ~ n) => Applyable a n where
apply :: Applicative f => f a -> AppFunc f (CountArgs a) a
instance (CountArgs a ~ Z) => Applyable a Z where
apply = id
{-# INLINE apply #-}
instance Applyable b n => Applyable (a -> b) (S n) where
apply f x = apply (f <*> x)
{-# INLINE apply #-}
-- | >>> lift (\x y z -> x ++ y ++ z) (Just "a") (Just "b") (Just "c")
-- Just "abc"
lift :: (Applyable a n, Applicative f) => (b -> a) -> (f b -> AppFunc f n a)
lift f x = apply (fmap f x)
{-# INLINE lift #-}
This example is adapted from Richard Eisenberg's thesis.
Part of the power of Haskell is delegating range checks to the type system (see for example Numeric.Natural). Is this possible to do for types whose set of values is defined once at runtime? I'd effectively like an Enum whose values are unknown at compile-time.
Edit: In terms of example usage:
-- Defines the list of allowed values
init :: [a] -> ?
-- Constructs a new instance
construct :: a -> ? -> Maybe Foo
-- Then just usable like an enum
bar :: Int -> Foo -> Bar
Ideally I'd be able to use things like Bounded on it too.
Your sample code is, unfortunately, too sparse to indicate what you really mean. I'm guessing you may be after dependent types, as n.m. suggested. If that is the case, you're likely better off looking at something like Agda instead of Haskell. If you want a somewhat safer version of what Daniel Wagner suggested, you can get it with the reflection package.
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
module DynEnum (.... not including newtype constructors) where
import Data.Reflection
import Data.Proxy
import Data.Set (Set, splitMember, size, lookupIndex, fromList, elemAt, member, findMin, findMax)
import Data.Foldable
import Data.Bool
import Data.Type.Coercion
-- Just Enum
newtype Limited a s = Limited { unLimited :: a }
type role Limited representational nominal
-- We can safely conflate types of values that come
-- from the same set.
coerceLimited :: (Reifies s (Set a), Reifies t (Set a), Ord a)
=> Maybe (Coercion (Limited a s) (Limited a t))
coerceLimited
| reflect (Proxy :: Proxy s) == reflect (Proxy :: Proxy t)
= Just Coercion
| otherwise = Nothing
instance (Ord a, Reifies s (Set a)) => Enum (Limited a s) where
toEnum i
| 0 <= i && i < size values = Limited $ elemAt i values
| otherwise = error "Limited toEnum: out of range"
where values = reflect (Proxy :: Proxy s)
fromEnum x = case lookupIndex (unLimited x) (reflect x) of
Nothing -> error "Limited fromEnum: out of range"
Just i -> i
enumFrom (Limited a) = case splitMember a (reflect (Proxy :: Proxy s)) of
(_, False, s) -> fmap Limited $ toList s
(_, True, s) -> Limited a : fmap Limited (toList s)
enumFromTo (Limited a) (Limited b) = case splitMember a (reflect (Proxy :: Proxy s)) of
(_, inclFirst, s) -> case splitMember b s of
(t, inclLast, _) -> bool id (Limited a:) inclFirst
. (map Limited (toList t) ++)
$ bool [] [Limited b] inclLast
initialize :: Ord a
=> [a]
-> (forall s . Enum (Limited a s) => Proxy s -> r)
-> r
initialize vals f = reify (fromList vals) f
construct :: forall s a . (Ord a, Reifies s (Set a)) => a -> Maybe (Limited a s)
construct x
| x `member` reflect (Proxy :: Proxy s) = Just (Limited x)
| otherwise = Nothing
newtype Bound a b = Bound a deriving (Enum)
type role Bound representational nominal
instance Reifies b (a, a) => Bounded (Bound a b) where
minBound = Bound . fst $ reflect (Proxy :: Proxy b)
maxBound = Bound . snd $ reflect (Proxy :: Proxy b)
initializeBounded :: (a, a)
-> (forall b . Bounded (Bound a b) => Proxy b -> r)
-> r
initializeBounded bounds f = reify bounds f
newtype LimitedB a s b = LimitedB (Bound (Limited a s) b)
deriving instance (Ord a, Reifies s (Set a)) => Enum (LimitedB a s b)
deriving instance Reifies b (Limited a s, Limited a s) => Bounded (LimitedB a s b)
initializeLimitedB :: Ord a
=> [a]
-> (forall s b . (Enum (LimitedB a s b), Bounded (LimitedB a s b)) => Proxy s -> Proxy b -> r)
-> r
initializeLimitedB [] _f = error "Cannot initialize LimitedB with an empty list"
initializeLimitedB vals f = reify set $ \ps ->
reify (Limited (findMin set), Limited (findMax set)) $ \pb ->
f ps pb
where
set = fromList vals
Perhaps a Set is suitable for your needs. We have:
initialize :: Ord a => [a] -> Set a
initialize = fromList
construct :: Ord a => a -> Set a -> Maybe a
construct x xs = guard (x `member` xs) >> return x
dynamicMinBound :: Set a -> Maybe a
dynamicMinBound xs = fst <$> minView xs
dynamicMaxBound :: Set a -> Maybe a
dynamicMaxBound xs = fst <$> maxView xs
enumerate :: Set a -> [a]
enumerate = toList
dynamicToEnum :: Int -> Set a -> Maybe a
dynamicToEnum n xs = guard (inRange n (0, size xs-1)) >> return (elemAt n xs)
dynamicFromEnum :: Ord a => a -> Set a -> Maybe Int
dynamicFromEnum = lookupIndex
I believe this covers the operations you asked for, though I could easily have misunderstood something -- your specification is not 100% clear to me.
Sometimes I come upon a need to return values of an existentially quantified type. This happens most often when I'm working with phantom types (for example representing the depth of a balanced tree). AFAIK GHC doesn't have any kind of exists quantifier. It only allows existentially quantified data types (either directly or using GADTs).
To give an example, I'd like to have functions like this:
-- return something that can be shown
somethingPrintable :: Int -> (exists a . (Show a) => a)
-- return a type-safe vector of an unknown length
fromList :: [a] -> (exists n . Vec a n)
So far, I have 2 possible solutions that I'll add as an answer, I'd be happy to know if anyone knows something better or different.
The standard solution is to create an existentially quantified data type. The result would be something like
{-# LANGUAGE ExistentialQuantification #-}
data Exists1 = forall a . (Show a) => Exists1 a
instance Show Exists1 where
showsPrec _ (Exists1 x) = shows x
somethingPrintable1 :: Int -> Exists1
somethingPrintable1 x = Exists1 x
Now, one can freely use show (somethingPrintable 42). Exists1 cannot be newtype, I suppose it's because it's necessary to pass around the particular implementation of show in a hidden context dictionary.
For type-safe vectors, one could proceed the same way to create fromList1 implementation:
{-# LANGUAGE GADTs #-}
data Zero
data Succ n
data Vec a n where
Nil :: Vec a Zero
Cons :: a -> Vec a n -> Vec a (Succ n)
data Exists1 f where
Exists1 :: f a -> Exists1 f
fromList1 :: [a] -> Exists1 (Vec a)
fromList1 [] = Exists1 Nil
fromList1 (x:xs) = case fromList1 xs of
Exists1 r -> Exists1 $ Cons x r
This works well, but the main drawback I see is the additional constructor. Each call to fromList1 results in an application of the constructor, which is immediately deconstructed. As before, newtype isn't possible for Exists1, but I guess without any type-class constraints the compiler could allow it.
I created another solution based on rank-N continuations. It doesn't need the additional constructor, but I'm not sure, if additional function application doesn't add a similar overhead. In the first case, the solution would be:
{-# LANGUAGE Rank2Types #-}
somethingPrintable2 :: Int -> ((forall a . (Show a) => a -> r) -> r)
somethingPrintable2 x = \c -> c x
now one would use somethingPrintable 42 show to get the result.
And, for the Vec data type:
{-# LANGUAGE RankNTypes, GADTs #-}
fromList2 :: [a] -> ((forall n . Vec a n -> r) -> r)
fromList2 [] c = c Nil
fromList2 (x:xs) c = fromList2 xs (c . Cons x)
-- Or wrapped as a newtype
-- (this is where we need RankN instead of just Rank2):
newtype Exists3 f r = Exists3 { unexists3 :: ((forall a . f a -> r) -> r) }
fromList3 :: [a] -> Exists3 (Vec a) r
fromList3 [] = Exists3 (\c -> c Nil)
fromList3 (x:xs) = Exists3 (\c -> unexists3 (fromList3 xs) (c . Cons x))
this can be made a bit more readable using a few helper functions:
-- | A helper function for creating existential values.
exists3 :: f x -> Exists3 f r
exists3 x = Exists3 (\c -> c x)
{-# INLINE exists3 #-}
-- | A helper function to mimic function application.
(?$) :: (forall a . f a -> r) -> Exists3 f r -> r
(?$) f x = unexists3 x f
{-# INLINE (?$) #-}
fromList3 :: [a] -> Exists3 (Vec a) r
fromList3 [] = exists3 Nil
fromList3 (x:xs) = (exists3 . Cons x) ?$ fromList3 xs
The main disadvantages I see here are:
Possible overhead with the additional function application (I don't know how much the compiler can optimize this).
Less readable code (at least for people not used to continuations).