While using applicative functors in Haskell I've often run into situations where I end up with repetitive code like this:
instance Arbitrary MyType where
arbitrary = MyType <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
In this example I'd like to say:
instance Arbitrary MyType where
arbitrary = applyMany MyType 4 arbitrary
but I can't figure out how to make applyMany (or something similar to it). I can't even figure out what the type would be but it would take a data constructor, an Int (n), and a function to apply n times. This happens when creating instances for QuickCheck, SmallCheck, Data.Binary, Xml serialization, and other recursive situations.
So how could I define applyMany?
Check out derive. Any other good generics library should be able to do this as well; derive is just the one I am familiar with. For example:
{-# LANGUAGE TemplateHaskell #-}
import Data.DeriveTH
import Test.QuickCheck
$( derive makeArbitrary ''MyType )
To address the question you actually asked, FUZxxl is right, this is not possible in plain vanilla Haskell. As you point out, it is not clear what its type should even be. It is possible with Template Haskell metaprogramming (not too pleasant). If you go that route, you should probably just use a generics library which has already done the hard research for you. I believe it is also possible using type-level naturals and typeclasses, but unfortunately such type-level solutions are usually difficult to abstract over. Conor McBride is working on that problem.
I think you can do it with OverlappingInstances hack:
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeFamilies, OverlappingInstances #-}
import Test.QuickCheck
import Control.Applicative
class Arbitrable a b where
convert :: Gen a -> Gen b
instance (Arbitrary a, Arbitrable b c) => Arbitrable (a->b) c where
convert a = convert (a <*> arbitrary)
instance (a ~ b) => Arbitrable a b where
convert = id
-- Should work for any type with Arbitrary parameters
data MyType a b c d = MyType a b c d deriving (Show, Eq)
instance Arbitrary (MyType Char Int Double Bool) where
arbitrary = convert (pure MyType)
check = quickCheck ((\s -> s == s) :: (MyType Char Int Double Bool -> Bool))
Not satisfied with my other answer, I have come up with an awesomer one.
-- arb.hs
import Test.QuickCheck
import Control.Monad (liftM)
data SimpleType = SimpleType Int Char Bool String deriving(Show, Eq)
uncurry4 f (a,b,c,d) = f a b c d
instance Arbitrary SimpleType where
arbitrary = uncurry4 SimpleType `liftM` arbitrary
-- ^ this line is teh pwnzors.
-- Note how easily it can be adapted to other "simple" data types
ghci> :l arb.hs
[1 of 1] Compiling Main ( arb.hs, interpreted )
Ok, modules loaded: Main.
ghci> sample (arbitrary :: Gen SimpleType)
>>>a bunch of "Loading package" statements<<<
SimpleType 1 'B' False ""
SimpleType 0 '\n' True ""
SimpleType 0 '\186' False "\208! \227"
...
Lengthy explanation of how I figured this out
So here's how I got it. I was wondering, "well how is there already an Arbitrary instance for (Int, Int, Int, Int)? I'm sure no one wrote it, so it must be derived somehow. Sure enough, I found the following in the docs for instances of Arbitrary:
(Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d) => Arbitrary (a, b, c, d)
Well, if they already have that defined, then why not abuse it? Simple types that are merely composed of smaller Arbitrary data types are not much different than just a tuple.
So now I need to somehow transform the "arbitrary" method for the 4-tuple so that it works for my type. Uncurrying is probably involved.
Stop. Hoogle time!
(We can easily define our own uncurry4, so assume we already have this to operate with.)
I have a generator, arbitrary :: Gen (q,r,s,t) (where q,r,s,t are all instances of Arbitrary). But let's just say it's arbitrary :: Gen a. In other words, a represents (q,r,s,t). I have a function, uncurry4, which has type (q -> r -> s -> t -> b) -> (q,r,s,t) -> b. We are obviously going to apply uncurry4 to our SimpleType constructor. So uncurry4 SimpleType has type (q,r,s,t) -> SimpleType. Let's keep the return value generic, though, because Hoogle doesn't know about our SimpleType. So remembering our definition of a, we have essentially uncurry4 SimpleType :: a -> b.
So I've got a Gen a and a function a -> b. And I want a Gen b result. (Remember, for our situation, a is (q,r,s,t) and b is SimpleType). So I am looking for a function with this type signature: Gen a -> (a -> b) -> Gen b. Hoogling that, and knowing that Gen is an instance of Monad, I immediately recognize liftM as the monadical-magical solution to my problems.
Hoogle saves the day again. I knew there was probably some "lifting" combinator to get the desired result, but I honestly didn't think to use liftM (durrr!) until I hoogled the type signature.
Here is what I'v got at least:
{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
module ApplyMany where
import Control.Applicative
import TypeLevel.NaturalNumber -- from type-level-natural-number package
class GetVal a where
getVal :: a
class Applicative f => ApplyMany n f g where
type Res n g
app :: n -> f g -> f (Res n g)
instance Applicative f => ApplyMany Zero f g where
type Res Zero g = g
app _ fg = fg
instance
(Applicative f, GetVal (f a), ApplyMany n f g)
=> ApplyMany (SuccessorTo n) f (a -> g)
where
type Res (SuccessorTo n) (a -> g) = Res n g
app n fg = app (predecessorOf n) (fg<*>getVal)
Usage example:
import Test.QuickCheck
data MyType = MyType Char Int Bool deriving Show
instance Arbitrary a => GetVal (Gen a) where getVal = arbitrary
test3 = app n3 (pure MyType) :: Gen MyType
test2 = app n2 (pure MyType) :: Gen (Bool -> MyType)
test1 = app n1 (pure MyType) :: Gen (Int -> Bool -> MyType)
test0 = app n0 (pure MyType) :: Gen (Char -> Int -> Bool -> MyType)
Btw, I think this solution is not very useful in real world. Especially without local type-classes.
Check out liftA2 and liftA3. Also, you can easily write your own applyTwice or applyThrice methods like so:
applyTwice :: (a -> a -> b) -> a -> b
applyTwice f x = f x x
applyThrice :: (a -> a -> a -> b) -> a -> b
applyThrice f x = f x x x
There's no easy way I can see to get the generic applyMany you're asking for, but writing trivial helpers such as these is neither difficult nor uncommon.
[edit] So it turns out, you'd think something like this would work
liftA4 f a b c d = f <$> a <*> b <*> c <*> d
quadraApply f x = f x x x x
data MyType = MyType Int String Double Char
instance Arbitrary MyType where
arbitrary = (liftA4 MyType) `quadraApply` arbitrary
But it doesn't. (liftA4 MyType) has a type signature of (Applicative f) => f Int -> f String -> f Double -> f Char -> f MyType. This is incompatible with the first parameter of quadraApply, which has a type signature of (a -> a -> a -> a -> b) -> a -> b. It would only work for data structures that hold multiple values of the same Arbitrary type.
data FourOf a = FourOf a a a a
instance (Arbitrary a) => Arbitrary (FourOf a) where
arbitrary = (liftA4 FourOf) `quadraApply` arbitrary
ghci> sample (arbitrary :: Gen (FourOf Int))
Of course you could just do this if you had that situation
ghci> :l +Control.Monad
ghci> let uncurry4 f (a, b, c, d) = f a b c d
ghci> samples <- sample (arbitrary :: Gen (Int, Int, Int, Int))
ghci> forM_ samples (print . uncurry4 FourOf)
There might be some language pragma that can shoehorn the "arbitrary" function into the more diverse data types. But that's currently beyond my level of Haskell-fu.
This is not possible with Haskell. The problem is, that your function will have a type, that depends on the numeric argument. With a type system that allows dependent types, that should be possible, but I guess not in Haskell.
What you can try is using polymorphism and tyeclasses to archieve this, but it could become hacky and you need a big bunch of extensions to satisfy the compiler.
Related
Using RankNTypes one can enforce various kinds of parametricity. For example, A id :: A:
newtype A = A { unA :: forall a. a -> a }
But how about cases where we only care about the parametricity of the function on its argument? For a specific kind of case, the following will work:
newtype X b = X { unX :: forall a. a -> (a, b) }
For example, X (\a -> (a, ())) :: X ().
I would like to understand how to (or whether one can) construct a parametricity test that works more generally for functions of the form \a -> (a, f a), where f may be constant (as above) or potentially parametric itself. This can't be accomplished with X. E.g., X (\a -> (a, id a)) is a type error. Can this be done?
Edit: I'd like to repose or elaborate on the question somewhat. Suppose we have a type of parameterized state transformers:
type PState i o a = i -> (a, o)
Suppose also that we are interested in statically enforcing that the a in an arbitrary m :: PState i o a does not depend on i in any way. In other words, is it possible to define a function f such that f m is well typed when m's value doesn't depend on the input (and in that case evaluates to m), and is not well typed otherwise?
You'll need to make an explicit type-level function to accomplish this. Normally quantified Type -> Type variables are actually assumed to be type constructors (injective functions), which is not sufficient here. But it is possible to have noninjective ones too, they're just called type families. The flip side to this is that you need some separate means of actually indexing which one you want, because type inference wouldn't work without that.
{-# LANGUAGE TypeFamilies, KindSignatures, EmptyDataDecls, TypeInType
, RankNTypes, UnicodeSyntax #-}
import Data.Kind
type family MyTyFun (f :: Type) (a :: Type) :: Type
newtype GState f = GState { unGS :: ∀ a . a -> (a, MyTyFun f a) }
data Af
type instance MyTyFun Af a = ()
type A = GState Af
data Xf b
type instance MyTyFun (Xf b) a = b
type X b = GState (Xf b)
data Wf
type instance MyTyFun Wf a = a
type W = GState Wf
> unGS (GState (\a -> (a, a)) :: W) 4
(4,4)
I was reading through the announcement of ClassyPrelude and got to here:
instance (b ~ c, CanFilterFunc b a) => CanFilter (b -> c) a where
filter = filterFunc
The writer then mentioned that this would not work:
instance (CanFilterFunc b a) => CanFilter (c -> c) a where
filter = filterFunc
Which makes sense to me, as c is completely unrelated to the constraint on the left.
However, what isn't mentioned in the article and what I don't understand is why this wouldn't work:
instance (CanFilterFunc b a) => CanFilter (b -> b) a where
filter = filterFunc
Could someone explain why this is different to the first mentioned definition? Perhaps a worked example of GHC type inference would be helpful?
Michael already gives a good explanation in his blog article, but I'll try to illustrate it with a (contrived, but relatively small) example.
We need the following extensions:
{-# LANGUAGE FlexibleInstances, TypeFamilies #-}
Let's define a class that is simpler than CanFilter, with just one parameter. I'm defining two copies of the class, because I want to demonstrate the difference in behaviour between the two instances:
class Twice1 f where
twice1 :: f -> f
class Twice2 f where
twice2 :: f -> f
Now, let's define an instance for each class. For Twice1, we fix the type variables to be the same directly, and for Twice2, we allow them to be different, but add an equality constraint.
instance Twice1 (a -> a) where
twice1 f = f . f
instance (a ~ b) => Twice2 (a -> b) where
twice2 f = f . f
In order to show the difference, let us define another overloaded function like this:
class Example a where
transform :: Int -> a
instance Example Int where
transform n = n + 1
instance Example Char where
transform _ = 'x'
Now we are at a point where we can see a difference. Once we define
apply1 x = twice1 transform x
apply2 x = twice2 transform x
and ask GHC for the inferred types, we get that
apply1 :: (Example a, Twice1 (Int -> a)) => Int -> a
apply2 :: Int -> Int
Why is that? Well, the instance for Twice1 only fires when source and target type of the function are the same. For transform and the given context, we don't know that. GHC will only apply an instance once the right hand side matches, so we are left with the unresolved context. If we try to say apply1 0, there will be a type error saying that there is still not enough information to resolve the overloading. We have to explicitly specify the result type to be Int in this case to get through.
However, in Twice2, the instance is for any function type. GHC will immediately resolve it (GHC never backtracks, so if an instance clearly matches, it's always chosen), and then try to establish the preconditions: in this case, the equality constraint, which then forces the result type to be Int and allows us to resolve the Example constraint, too. We can say apply2 0 without further type annotations.
So this is a rather subtle point about GHC's instance resolution, and the equality constraint here helps GHC's type checker along in a way that requires fewer type annotations by the user.
to complete the #kosmikus answer
same applies to purescript - you need equality constraint to derive type properly (you can try here http://try.purescript.org)
module Main where
import Prelude
-- copied from https://github.com/purescript/purescript-type-equality/blob/master/src/Type/Equality.purs
class TypeEquals a b | a -> b, b -> a where
to :: a -> b
from :: b -> a
instance refl :: TypeEquals a a where
to a = a
from a = a
-----------------
class Twice1 f where
twice1 :: f -> f
class Twice2 f where
twice2 :: f -> f
instance mytwice1 :: Twice1 (a -> a) where
twice1 f = f >>> f
instance mytwice2 :: TypeEquals a b => Twice2 (a -> b) where
twice2 f = f >>> from >>> f
class Example a where
transform :: Int -> a
instance exampleInt :: Example Int where
transform n = n + 1
instance exampleChar :: Example Char where
transform _ = 'x'
{--
-- will raise error
-- No type class instance was found for Main.Twice1 (Int -> t1)
apply1 x = twice1 transform x
-- to resolve error add type declaration
apply1 :: Int -> Int
--}
-- compiles without error and manual type declaration, has type Int -> Int automatically
apply2 x = twice2 transform x
But in idris you don't
module Main
import Prelude
interface Twice f where
twice : f -> f
Twice (a -> a) where
twice f = f . f
interface Example a where
transform : Int -> a
Example Int where
transform n = n + 1
Example Char where
transform _ = 'x'
-- run in REPL to see that it derives properly:
-- $ idris src/15_EqualityConstraint_Twice_class.idr
-- *src/15_EqualityConstraint_Twice_class> :t twice transform
-- twice transform : Int -> Int
-- Summary:
-- in idris you dont need equality constaint to derive type of such functions properly
I'm working on an HList implementation and I'm stuck trying to implement a map function for it. I've tried a lot of different approaches but with each one I reach compiler errors related to that function.
Following is an example of how I want to use a generic function Just to apply it to all elements of the input data structure.
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
-- | An input heterogenous data structure
recursivePairs :: (Int, (Char, (Bool, ())))
recursivePairs = (1, ('a', (True, ())))
-- | This is how I want to use it
recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool, ())))
recursivePairs' = hMap Just recursivePairs
class HMap f input output where
hMap :: f -> input -> output
-- | A counterpart of a Nil pattern match for a list
instance HMap f () () where
hMap _ _ = ()
-- | A counterpart of a Cons pattern match for a list
instance
( HMap f iTail oTail,
Apply f iHead oHead ) =>
HMap f (iHead, iTail) (oHead, oTail)
where
hMap f (head, tail) = (apply f head, hMap f tail)
class Apply f input output where
apply :: f -> input -> output
instance Apply (input -> output) input output where
apply = id
With this I'm getting the following compiler error:
No instance for (Apply (a0 -> Maybe a0) Int (Maybe Int))
arising from a use of `hMap'
The type variable `a0' is ambiguous
Is there at all a way to solve this and if not then why?
The problem is that you are trying to use a polymorphic function with different arguments, but your Apply instance takes a function (a mono-type). You can easily fix this multiple ways
data JustIfy = JustIfy
instance Apply JustIfy a (Maybe a) where
apply _ = Just
recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool, ())))
recursivePairs' = hMap JustIfy recursivePairs
works with your code just fine
EDIT: A more general approach to the same thing is (requiring RankNTypes)
--A "universal" action that works on all types
newtype Univ f = Univ (forall x. x -> f x)
instance Apply (Univ f) x (f x) where
apply (Univ f) x = f x
recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool, ())))
recursivePairs' = hMap (Univ Just) recursivePairs
or if you are using a recent ish version of GHC and are willing to turn on more extensions
newtype Univ' c f = Univ' (forall x. c x => x -> f x)
instance c x => Apply (Univ' c f) x (f x) where
apply (Univ' f) x = f x
class All x
instance All x
recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool, ())))
recursivePairs' = hMap (Univ' Just :: Univ' All Maybe) recursivePairs
which is nice since then it lets you do things like include a "show" in the function you map with.
For a more general solution, check out Oleg's Type level lambda caclulus which allows you to write code at the value level and then auto-magically infers the appropriate type level program. Unfortunetly, Oleg's solution is at this point rather old, and uses a nominal implementation of the LC which I don't particularly like. I've been thinking about how to do better, but might hold off until deciable equality comes to type families.
My view is that HLists should these days be done using GADTs and DataKinds rather than tuples. Type families are preferable to functional dependencies, but currently are more limited because they lack decidable equality.
Although the following does not exactly answer the question (so I won't be accepting it), it does solve the problem concerning mapping the structure without requiring any additional instances for applicative functors:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
import Control.Applicative
main = do
print $ (hPure recursivePairs :: (Maybe Int, (Maybe Char, (Maybe Bool, ()))))
print $ (hPure recursivePairs :: ([Int], ([Char], ([Bool], ()))))
recursivePairs :: (Int, (Char, (Bool, ())))
recursivePairs = (1, ('a', (True, ())))
class HPure input output where
hPure :: input -> output
instance HPure () () where
hPure _ = ()
instance
( Applicative f,
HPure iTail oTail ) =>
HPure (iHead, iTail) (f iHead, oTail)
where hPure (iHead, iTail) = (pure iHead, hPure iTail)
Outputs:
(Just 1,(Just 'a',(Just True,())))
([1],("a",([True],())))
I was reading through the announcement of ClassyPrelude and got to here:
instance (b ~ c, CanFilterFunc b a) => CanFilter (b -> c) a where
filter = filterFunc
The writer then mentioned that this would not work:
instance (CanFilterFunc b a) => CanFilter (c -> c) a where
filter = filterFunc
Which makes sense to me, as c is completely unrelated to the constraint on the left.
However, what isn't mentioned in the article and what I don't understand is why this wouldn't work:
instance (CanFilterFunc b a) => CanFilter (b -> b) a where
filter = filterFunc
Could someone explain why this is different to the first mentioned definition? Perhaps a worked example of GHC type inference would be helpful?
Michael already gives a good explanation in his blog article, but I'll try to illustrate it with a (contrived, but relatively small) example.
We need the following extensions:
{-# LANGUAGE FlexibleInstances, TypeFamilies #-}
Let's define a class that is simpler than CanFilter, with just one parameter. I'm defining two copies of the class, because I want to demonstrate the difference in behaviour between the two instances:
class Twice1 f where
twice1 :: f -> f
class Twice2 f where
twice2 :: f -> f
Now, let's define an instance for each class. For Twice1, we fix the type variables to be the same directly, and for Twice2, we allow them to be different, but add an equality constraint.
instance Twice1 (a -> a) where
twice1 f = f . f
instance (a ~ b) => Twice2 (a -> b) where
twice2 f = f . f
In order to show the difference, let us define another overloaded function like this:
class Example a where
transform :: Int -> a
instance Example Int where
transform n = n + 1
instance Example Char where
transform _ = 'x'
Now we are at a point where we can see a difference. Once we define
apply1 x = twice1 transform x
apply2 x = twice2 transform x
and ask GHC for the inferred types, we get that
apply1 :: (Example a, Twice1 (Int -> a)) => Int -> a
apply2 :: Int -> Int
Why is that? Well, the instance for Twice1 only fires when source and target type of the function are the same. For transform and the given context, we don't know that. GHC will only apply an instance once the right hand side matches, so we are left with the unresolved context. If we try to say apply1 0, there will be a type error saying that there is still not enough information to resolve the overloading. We have to explicitly specify the result type to be Int in this case to get through.
However, in Twice2, the instance is for any function type. GHC will immediately resolve it (GHC never backtracks, so if an instance clearly matches, it's always chosen), and then try to establish the preconditions: in this case, the equality constraint, which then forces the result type to be Int and allows us to resolve the Example constraint, too. We can say apply2 0 without further type annotations.
So this is a rather subtle point about GHC's instance resolution, and the equality constraint here helps GHC's type checker along in a way that requires fewer type annotations by the user.
to complete the #kosmikus answer
same applies to purescript - you need equality constraint to derive type properly (you can try here http://try.purescript.org)
module Main where
import Prelude
-- copied from https://github.com/purescript/purescript-type-equality/blob/master/src/Type/Equality.purs
class TypeEquals a b | a -> b, b -> a where
to :: a -> b
from :: b -> a
instance refl :: TypeEquals a a where
to a = a
from a = a
-----------------
class Twice1 f where
twice1 :: f -> f
class Twice2 f where
twice2 :: f -> f
instance mytwice1 :: Twice1 (a -> a) where
twice1 f = f >>> f
instance mytwice2 :: TypeEquals a b => Twice2 (a -> b) where
twice2 f = f >>> from >>> f
class Example a where
transform :: Int -> a
instance exampleInt :: Example Int where
transform n = n + 1
instance exampleChar :: Example Char where
transform _ = 'x'
{--
-- will raise error
-- No type class instance was found for Main.Twice1 (Int -> t1)
apply1 x = twice1 transform x
-- to resolve error add type declaration
apply1 :: Int -> Int
--}
-- compiles without error and manual type declaration, has type Int -> Int automatically
apply2 x = twice2 transform x
But in idris you don't
module Main
import Prelude
interface Twice f where
twice : f -> f
Twice (a -> a) where
twice f = f . f
interface Example a where
transform : Int -> a
Example Int where
transform n = n + 1
Example Char where
transform _ = 'x'
-- run in REPL to see that it derives properly:
-- $ idris src/15_EqualityConstraint_Twice_class.idr
-- *src/15_EqualityConstraint_Twice_class> :t twice transform
-- twice transform : Int -> Int
-- Summary:
-- in idris you dont need equality constaint to derive type of such functions properly
I'm building an API between two models. I don't care if it returns a [] or Seq or anything Foldable is fine. But if I try to do that, I get errors.
module Main where
import Prelude hiding (foldr)
import Data.Foldable
import Data.Sequence
data Struct = Struct
main = do
print $ foldr (+) 0 $ list Struct
print $ foldr (+) 0 $ listFree Struct
listFree :: Foldable f => a -> f Int
listFree s = singleton 10
class TestClass a where
list :: Foldable f => a -> f Int
instance TestClass Struct where
list s = singleton 10
Both the listFree and the list definitions give the same error:
TestFoldable.hs:19:12:
Could not deduce (f ~ [])
from the context (Foldable f)
bound by the type signature for
list :: Foldable f => Struct -> f Int
at TestFoldable.hs:19:3-15
`f' is a rigid type variable bound by
the type signature for list :: Foldable f => Struct -> f Int
at TestFoldable.hs:19:3
In the expression: [10]
In an equation for `list': list s = [10]
In the instance declaration for `TestClass Struct'
Why is that? And what is the "right" way to accomplish what I'm trying to do here?
What I'm trying to accomplish is to hide the implementation from the caller. The actual data structure might be a Seq, IntMap, or anything else and most likely is not a list.
I'm getting responses that say "just return a list". But that means conversion, doesn't it? What if it's a 1,000,000 element structure? Converting it to an intermediate data structure just because of limitations of the API seems a poor solution.
And this is a general problem. How does one have a return value that conforms to some API? To hide the concrete implementation so the implementer is free to choose whatever structure is best for them and can change it without having to change the users of the API.
Another way of putting it is: how can I return an interface instead of a concrete type?
Closing Note:
The Haskell community on StackOverflow is (SuperlativeCompliment c => forall c. c)
Existential quantification seems like the general solution to this situation.
Another possibility to consider, which is not a general solution but might have worked for this specific case, that might avoid the extra wrapper value required by existential solution is to return a closure of the fold for the client:
list :: a -> ((Int -> b -> b) -> b -> b)
list = \f a0 -> foldr f a0 (singleton 10)
Why is that?
The type Foldable f => a -> f Int does not mean that the function might return any foldable it wants. It means that the function will return whichever type the user wants. I.e. if the user uses the function in a context where a list is required that should work and if he uses it in a context where a Seq is required that should also work. Since this is clearly not the case with your definition, it doesn't match its type.
And what is the "right" way to accomplish what I'm trying to do here?
The easiest way would be to just make your function return a list.
However if you do need to hide the fact that you're using lists from your users, the easiest way would be to create a wrapper type around the list and not export that type's constructor. I.e. something like:
module Bla (ListResult(), list) where
data ListResult a = ListResult [a]
instance Foldable (ListResult a) where
foldr op s (ListResult xs) = foldr op s xs
list s = ListResult [10]
Now if the user imports your module, it can fold over a ListResult because it's foldable, but it can't unpack it to get at the list because the constructor is not exported. So if you later change ListResult's definition to data ListResult a = ListResult (Seq a) and list to also use a Seq instead of a list, that change will be completely invisible to the user.
sepp2k already provided a good answer, but allow me to take a similar but slightly different angle. What you have done is provide result-type polymorphism. You wrote:
listFree :: Foldable f => a -> f Int
What this does is promise that you can produce any foldable that the user may need. You, of course, could never keep this promise because Foldable doesn't provide any constructor-like functions.
So what you're trying to do deals with generics. You want to make a weak promise: the function listFree will produce some Foldable, but in the future, it may change. You might implement it with a regular list today, but later, you might re-implement it with something else. And you want this implementation detail to be just that: an implementation detail. You want the contract for that function (the type signature) to remain the same.
Sounds like a job for yet another weird and confusing Haskell extension! Existential Quantification!
{-# LANGUAGE ExistentialQuantification #-}
import Prelude hiding (foldr, foldl, foldr1, foldl1)
import Data.Foldable
data SomeFoldable a = forall f. Foldable f => F (f a)
foo :: SomeFoldable Int
foo = F [1,2,3]
Here I've provide a value foo, but it has the type SomeFoldable Int. I'm not telling you which Foldable it is, simply that it is some foldable. SomeFoldable can easily be made an instance of Foldable, for convenience.
instance Foldable SomeFoldable where
fold (F xs) = fold xs
foldMap f (F xs) = foldMap f xs
foldr step z (F xs) = foldr step z xs
foldl step z (F xs) = foldl step z xs
foldr1 step (F xs) = foldr1 step xs
foldl1 step (F xs) = foldl1 step xs
Now we can do Foldable things with foo, for example:
> Data.Foldable.sum foo
6
But we can't do anything with it besides what Foldable exposes:
> print foo
No instance for (Show (SomeFoldable Int)) blah blah blah
It's easy to adapt your code to work as desired:
data Struct = Struct
main = do
print $ foldr (+) 0 $ list Struct
print $ foldr (+) 0 $ listFree Struct
listFree :: a -> SomeFoldable Int
listFree s = F [10]
class TestClass a where
list :: a -> SomeFoldable Int
instance TestClass Struct where
list s = F [10]
But remember, Existential Quantification has its drawbacks. There is no way to unwrap SomeFoldable to get the concrete Foldable underneath. The reason for this is the same reason that your function signature was wrong at the beginning: it promises result-type polymorphism: a promise it cannot keep.
unwrap :: Foldable f => SomeFoldable a -> f a -- impossible!
unwrap (F xs) = xs -- Nope. Keep dreaming. This won't work.
The Foldable class only provides methods for destructing instances of Foldable, and none for constructing instances. The complete list of class methods is reproduced below:
class Foldable t where
fold :: Monoid m => t m -> m
foldMap :: Monoid m => (a -> m) -> t a -> m
foldr :: (a -> b -> b) -> b -> t a -> b
foldl :: (a -> b -> a) -> a -> t b -> a
foldr1 :: (a -> a -> a) -> t a -> a
foldl1 :: (a -> a -> a) -> t a -> a
You can see that the return type of these methods never has a "t foo" type. So you cannot construct a value that is polymorphic in which Foldable instance you choose.
However, there are classes over type constructors for which the constructor appears in the return type of at least one method. For instance, there is
class Pointed p where
point :: a -> p a
provided by the pointed package. There is also the Monoid class provided by base:
class Monoid m where
mempty :: m
mappend :: m -> m -> m
mconcat :: [m] -> m
You could combine these two classes like so:
points :: (Pointed p, Monoid (p a)) => [a] -> p a
points = mconcat . map point
For example, in ghci:
> points [7,3,8] :: Set Int
fromList [3,7,8]
> points [7,3,8] :: First Int
First { getFirst = Just 7 }
> points [7,3,8] :: Last Int
Last { getLast = Just 8 }
> points [7,3,8] :: [Int]
[7,3,8]
> points [7,3,8] :: Seq Int
fromList [7,3,8]
etc.
As sepp2k said in his answer,
the problem is that we must have a monomorph return type.
Like a list in his answer.
However, we can still return a wrappertype that has a named type,
FoldableContainer, yet it is Foldable.
To achieve this we need GADTts.
{-# LANGUAGE GADTs #-}
module Main where
import Prelude hiding (foldr)
import Data.Foldable
data Struct = Struct
data FoldableContainer a where
F :: Foldable f => f a -> FoldableContainer a
instance Foldable FoldableContainer where
foldMap g (F f) = foldMap g f
main = do
print $ foldr (+) 0 $ list Struct
print $ foldr (+) 0 $ listFree Struct
listFree :: a -> FoldableContainer Int
listFree s = F [10]
class TestClass a where
list :: a -> FoldableContainer Int
instance TestClass Struct where
list s = F [10]
Note however that while this works it might as some say indeed be better
to just return a list. Why? First of all we create no extra type,
and second of all, each constructed F will need to carry alongside
the Foldable dictionary since it isn't known at compile time.
I don't know how much performence penalty this is but it must not be forgotten.
On the other hand we don't need lists as intermedite types anymore,
that is using sum on Set Int need not first be converted to a [Int].
The updated question has a very different answer. (Since my other answer is a good one, but answering a different question, I'm going to leave it.)
Create an abstract data type. The short of it is to define a new type in your module
newtype Struct a = Struct [a]
where here I've assumed for now that [a] is the concrete implementation that you want to hide. Then, you add a Foldable instance.
deriving instance Foldable Struct
-- could do this on the newtype definition line above,
-- but it doesn't fit with the flow of the answer
At the module boundary, you hide the actual implementation by exporting the Struct type, but not the Struct constructor. The only thing your callers will be able to do with a Struct a is call Foldable methods on it.