I am trying to use quickcheck to generate random arguments of a given function (assuming all its types have Arbitrary instance and Show instance) along with the evaluation of the function at those arguments. I just need to print the values of arguments and evaluated answer afterwards. So I expect a function with following type
randomEvaluate :: Testable a => a -> IO ( [String] -- arguments
, String ) -- Answer after evaluating
-- IO is just needed to get a new random number generator. If I pass a generator then I think probably I will not need IO here.
I am still not sure about the type here but I think Testable a would do.
I am still unable to actually get what I need. I am all confused in the mess of quickcheck datatypes Rose, Result etc.
UPDATE
Suppose I have a function
add :: Int -> Int -> Int
add a b = a+b
Then I assume a behavior like
> randomEvaluate add
(["1","3"],"4")
where 1 and 3 are random values generated for Int and 4 is f 1 3.
I don’t think that you can use much of the QuickCheck code besides the modules Test.QuickCheck.Arbitrary and Test.QuickCheck.Gen.
One parameter only
Here is some simple code that provides what you need for functions with one argument only:
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Gen
import System.Random
randomEvaluate :: (Arbitrary a, Show a, Show b) => (a -> b) -> IO (String, String)
randomEvaluate f = do
stdGen <- newStdGen
let x = unGen arbitrary stdGen 1000
let y = f x
return (show x, show y)
And here you can see it in action:
*Main> randomEvaluate (\(a,b) -> a + b)
("(-292,-655)","-947")
*Main> randomEvaluate (\(a,b) -> a + b)
("(586,-905)","-319")
*Main> randomEvaluate (\(a,b) -> a + b)
("(547,-72)","475")
As you can see it is possible to use it with functions with more than one argument if you uncurry it. If that is not sufficient things become a little bit more difficult, but should be posssible with some type class trickery.
Multiple parameters, return type marked explicitly
Here is an approach that requires “only” to wrap the return value of the function in a newtype. (This might be avoidable with non-Haskell98-features):
class RandEval a where
randomEvaluate :: StdGen -> a -> ([String], String)
newtype Ret a = Ret a
instance Show a => RandEval (Ret a) where
randomEvaluate _ (Ret x) = ([], show x)
instance (Show a, Arbitrary a, RandEval b) => RandEval (a -> b) where
randomEvaluate stdGen f = (show x : args, ret)
where (stdGen1, stdGen2) = split stdGen
x = unGen arbitrary stdGen1 1000
(args, ret) = randomEvaluate stdGen2 (f x)
doRandomEvaluate :: RandEval a => a -> IO ([String], String)
doRandomEvaluate f = do
stdGen <- newStdGen
return $ randomEvaluate stdGen f
See it in action here:
*Main> doRandomEvaluate (\a b -> Ret (a && b))
(["False","True"],"False")
*Main> doRandomEvaluate (\a b -> Ret (a + b))
(["944","758"],"1702")
*Main> doRandomEvaluate (\a b c -> Ret (a + b + c))
(["-274","413","865"],"1004")
*Main> doRandomEvaluate (\a b c d -> Ret (a + b + c + d))
(["-61","-503","-704","-877"],"-2145")
Multiple parameters with language extensions
If it is also undesirable to have to explicitly mark the return value, this works, but uses language extensions:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Gen
import System.Random
import Control.Arrow
class RandEval a where
randomEvaluate :: StdGen -> a -> ([String], String)
instance (Show a, Arbitrary a, RandEval b) => RandEval (a -> b) where
randomEvaluate stdGen f = first (show x:) $ randomEvaluate stdGen2 (f x)
where (stdGen1, stdGen2) = split stdGen
x = unGen arbitrary stdGen1 1000
instance Show a => RandEval a where
randomEvaluate _ x = ([], show x)
doRandomEvaluate :: RandEval a => a -> IO ([String], String)
doRandomEvaluate f = do
stdGen <- newStdGen
return $ randomEvaluate stdGen f
And here is the original use case from the posting:
*Main> doRandomEvaluate ( (+) :: Int -> Int -> Int )
(["-5998437593420471249","339001240294599646"],"-5659436353125871603")
But now you are at the whims of how GHC resolves overlapping instances. E.g. even with this nice (but also non-Haskell98) instance to show boolean functions:
type BoolFun a = Bool -> a
instance Show a => Show (BoolFun a) where
show f = "True -> " ++ show (f True) ++ ", False -> " ++ show (f False)
aBoolFun :: Bool -> BoolFun Bool
aBoolFun x y = x && y
you do not see this instance in use in doRandomEvaluate:
*Main> doRandomEvaluate aBoolFun
(["False","False"],"False")
With the original solution, you do:
*Main> doRandomEvaluate (Ret . aBoolFun)
(["False"],"True -> False, False -> False")
*Main> doRandomEvaluate (Ret . aBoolFun)
(["True"],"True -> True, False -> False")
A warning
But note that this is a slippery slope. A small change to the code above, and it stops working in GHC 7.6.1 (but still works in GHC 7.4.1):
instance (Show a, Arbitrary a, RandEval b) => RandEval (a -> b) where
randomEvaluate stdGen f = (show x:args, ret)
where (stdGen1, stdGen2) = split stdGen
x = unGen arbitrary stdGen1 1000
(args, ret) = randomEvaluate stdGen2 (f x)
SPJ explains why this is not really a bug – to me a clear sign that this approach is pushing the type class hackery a bit too far.
QuickCheck is stunningly simple:
Prelude> import Test.QuickCheck
A simple driver function is provided:
Prelude Test.QuickCheck> :t quickCheck
quickCheck :: Testable prop => prop -> IO ()
So define something that has a type found in 'Testable':
Prelude Test.QuickCheck> let prop_commut a b = a + b == b + a
Prelude Test.QuickCheck> :t prop_commut
prop_commut :: (Eq a, Num a) => a -> a -> Bool
And run it:
Prelude Test.QuickCheck> quickCheck prop_commut
+++ OK, passed 100 tests.
For a fuller treatment see RWH
Related
I have next two elements:
x :: Maybe t
y :: [(String, t)]
And I have a function:
foo :: t -> a
How can I implement polymorphic function that can work both on x and y with foo to collect results in list? More specifically, I need to put something instead of ??? here:
mapToList :: ??? => (t -> a) -> ??? t -> [a]
And I want to call with less boilerplate possible, most closest option to this is preferable:
mapToList foo x
mapToList foo y
Something naive like this doesn't work :(
mapToList :: Foldable f => (t -> a) -> f t -> [a]
mapToList extractor = map extractor . toList
mapToList #Maybe foo x
mapToList #([] ((,) String)) foo y
I was looking at Compose but didn't manage to figure out how to apply it to my problem in nice simple way. I can use Compose to generalize somehow but my solution is not satisfactory. I can always use map for lists and just maybe [] foo on Maybe's. But I wonder, is there nice way to generalize both use cases?
Not sure this helps at all since it's just shifting the boilerplate away from the call site, but:
{-# LANGUAGE FlexibleInstances,FunctionalDependencies,RankNTypes #-}
import Data.Functor.Compose (Compose(Compose))
import Data.Foldable
class AsFoldable x a | x -> a where
withFoldable :: (forall f. (Foldable f) => f a -> b) -> x -> b
instance AsFoldable [(String,a)] a where
withFoldable f = f . Compose
instance AsFoldable (Maybe a) a where
withFoldable = id
x :: Maybe Int
x = Just 3
y :: [(String,Int)]
y = [("A",5),("B",6)]
mapToList :: (AsFoldable x t) => (t -> a) -> x -> [a]
mapToList f = withFoldable (map f . toList)
main = do
print $ mapToList (+1) x
print $ mapToList (+1) y
How would I use pattern matching in order to exclude certain types of inputs? For instance given the following:
f list k =
if null list
then []
else head list + k : f (tail list) k
How can I use pattern matching to make f s/t it only allows Int and Integer but not Double or Float?
As suchtgott explained, you should not actually try to limit your function to exactly Int and Integer; you probably want to use an Integral constraint.
Suppose, for fun, that you really did want to limit it just like that. The way to do this in Haskell 98 is a bit weird (jump down to the break to see how this is done in GHC Haskell:
class Integral a => IntOrInteger a where
intOrInteger :: Either (f a -> f Int) (f a -> f Integer)
instance IntOrInteger Int where
intOrInteger = Left id
instance IntOrInteger Integer where
intOrInteger = Right id
How do you use such a thing? Well, to start off with
intOrIntegerSimple :: IntOrInteger a => Either (a -> Int) (a -> Integer)
intOrIntegerSimple = case intOrInteger of
Left f -> Left (runIdentity . f . Identity)
Right f -> Right (runIdentity . f . Identity)
But how do you flip it around, and turn an Int or Integer back to an instance of IntOrInteger?
newtype Switch f a i = Switch {runSwitch :: f i -> f a}
intOrInteger' :: IntOrInteger a => Either (f Int -> f a) (f Integer -> f a)
intOrInteger' = case intOrInteger of
Left f -> Left (runSwitch (f (Switch id)))
Right f -> Right (runSwitch (f (Switch id)))
intOrIntegerSimple' :: IntOrInteger a => Either (Int -> a) (Integer -> a)
intOrIntegerSimple' = case intOrInteger' of
Left f -> Left (runIdentity . f . Identity)
Right f -> Right (runIdentity . f . Identity)
When you don't really care whether you have an Int or an Integer, but want to be sure you really have one of them, you have to watch out for invalid instances. What might an invalid instance look like? This is one option:
instance IntOrInteger Word where
intOrInteger = Left (const undefined)
To just test that the instance is valid, you can use this (importing Data.Proxy):
ensureIntOrInteger :: IntOrInteger a => Proxy a -> ()
ensureIntOrInteger p = case intOrInteger of
Left f -> f p `seq` ()
Right f -> f p `seq` ()
The result of ensureIntOrInteger will be defined if and only if the type a is actually an Int or an Integer.
Nice; it works. But in practice it's pretty nasty to use. You can do much better with a few GHC extensions:
{-# LANGUAGE GADTs, TypeFamilies, TypeOperators, ConstraintKinds,
UndecidableInstances, UndecidableSuperClasses, DataKinds #-}
-- In 8.0 and later, Constraint is also available from Data.Kind
import GHC.Exts (Constraint)
import Data.Type.Equality ((:~:)(..))
import GHC.TypeLits (TypeError, ErrorMessage (..))
type family IntOrIntegerC a :: Constraint where
IntOrIntegerC Int = ()
IntOrIntegerC Integer = ()
IntOrIntegerC t = TypeError ('ShowType t :<>:
'Text " is not an Int or an Integer.")
class (Integral a, IntOrIntegerC a) => IntOrInteger a where
intOrInteger :: Either (a :~: Int) (a :~: Integer)
instance IntOrInteger Int where
intOrInteger = Left Refl
instance IntOrInteger Integer where
intOrInteger = Right Refl
With this formulation, the IntOrIntegerC constraint family blocks out any invalid types without your needing to do anything, giving a useful error message if someone tries to write a bogus instance. And if you actually do need to use the equality evidence, it's simply a matter of pattern matching on intOrInteger or using the various handy functions in Data.Type.Equality.
A point of style: using head and tail is generally discouraged in Haskell. We prefer to pattern match instead. Your function could be written
f [] _ = []
f (x : xs) k = x + k : f xs k
f/mapAdd implements a map. map is
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x : xs) = f x : map f xs
and can be used to formulate mapAdd:
Prelude> mapAdd n = map (+ n)
Prelude> mapAdd 3 [1,2,3,4]
[4,5,6,7]
GHCi's :type command tells you the automatically inferred type signature of mapAdd:
Prelude> :type mapAdd
mapAdd :: Num b => b -> [b] -> [b]
Here, mapAdd's bs are constrained to the general numerical type class Num. You can explicitly constrain to the type class Integral, which (basically) exclusively contains the data types Int, and Integer. Integral is a subclass of Num.
Prelude> :{
Prelude| mapAdd :: Integral a => a -> [a] -> [a]
Prelude| mapAdd n = map (+ n)
Prelude| :}
Prelude> :t mapAdd
mapAdd :: Integral a => a -> [a] -> [a]
mapAdd n = map (+ n) is pointfree for mapAdd n lst = map (+ n) lst.
You can create a dumb type class with instances only for Int and Integer and then use a type constraint:
class (Num a) => IntOrInteger a
instance IntOrInteger Int
instance IntOrInteger Integer
f :: (IntOrInteger a) => [a] -> a -> [a]
f list k =
if null list
then []
else head list + k : f (tail list) k
Then if you use f with Int, it will compile:
> f [1,2,3] 1
[2,3,4]
But it will not compile with Double:
> f [1,2,3] (1::Double)
<interactive>:19:1: error:
* No instance for (IntOrInteger Double) arising from a use of `f'
* In the expression: f [1, 2, 3] (1 :: Double)
In an equation for `it': it = f [1, 2, 3] (1 :: Double)
There are a lot of ways to constrain types, the most direct is just with type families.
type family Elem x xs :: Constraint where
Elem x (x ': xs) = ()
Elem x (y ': xs) = Elem x xs
Elem x '[] = TypeError ('ShowType x :<>: 'Text " is not a permitted type.")
type a ~~ b = Elem a b
function :: (a ~~ [Int, Integer], Num a) => [a] -> [a]
This allows you to white list a set of types. You won't know which one in particular you have though, that's more complicated.
However, you said you wanted to exclude certain types, so perhaps you want a black list. We simply flip the first and last case:
type family NotElem x xs :: Constraint where
NotElem x (x ': xs) = TypeError ('ShowType x :<>: 'Text " is a forbidden type.")
NotElem x (y ': xs) = NotElem x xs
NotElem x '[] = ()
type a !~~ b = NotElem a b
function :: (a !~~ [Double, Float], Num a) => [a] -> [a]
function will now accept any Num type that is not a Double or Float.
However, there's no reason to actually do any of this for your example function. You lose nothing at all by allowing it to work on the full range of Num types. In fact, these hijinks will at the least cost you a tiny smidgen more time on type checking, or if you go further and do reflection based things, possibly run time overhead as well.
For example, typing :t ap in GHCi gives the result
ap :: Monad m => m (a -> b) -> m a -> m b
If I already know the Monad instance I'm going to use is ((->) r), how can I query for the type of ap for that specific instance?
As Lazersmoke said as a comment you can use the TypeApplications extension that was introduced in GHC 8.0.
In GHCi:
λ > :set -XTypeApplications
λ > import Control.Monad
λ > :t ap #((->) _)
ap #((->) _) :: (t -> a -> b) -> (t -> a) -> t -> b
You can use visible type application feature to specify parametric types. You can look at functions in more creative way: functions in Haskell can be applied to not only values of some types, but also to types of that values. But to pass type you should somehow specify (with prepending #) that you're passing types (because types are not first-class objects in Haskell yet).
So here how it works:
λ: :set -XTypeApplications
λ: :t ap #((->) Int)
ap #((->) Int) :: (Int -> a -> b) -> (Int -> a) -> Int -> b
The only limitation of such approach is that you can't use type variables in ghci, you should use specific types (Int instead of r) but this is not big deal.
ADVANCED SECTION
Well, actually you can, but it's tricky:
λ: :set -XExplicitForAll
λ: :set -XPartialTypeSignatures
λ: :set -XScopedTypeVariables
λ: :{
λ| foo :: forall r . _
λ| foo = ap #((->) r)
λ| :}
<interactive>:28:19: warning: [-Wpartial-type-signatures]
• Found type wildcard ‘_’
standing for ‘(r -> a -> b) -> (r -> a) -> r -> b’
λ: :t foo
foo :: (r -> a -> b) -> (r -> a) -> r -> b
UPD: You can actually use placeholders instead of type variables (see another answer). But if you want to specify exact names use approach from above.
λ: :t ap #((->) _)
ap #((->) _) :: (t -> a -> b) -> (t -> a) -> t -> b
/ADVANCED SECTION
One more thing to say about this approach: you should do something more if your functions have several type parameters and you want to specify exact one. Types are passed one by one from left to right just as simple arguments in some function like bar :: Int -> String -> Double. If you want to fix first argument of bar you should write bar 5 and if you want to fix second, then, well, you can write something like \n -> bar n "baz" but this doesn't work with type application. You need to know two things:
Order of types.
How to specify desired type.
Consider next function:
λ: :t lift
lift :: (Monad m, MonadTrans t) => m a -> t m a
We want be able to specify m and t type variables. Because Haskell has no named type variables (yet) you can't write :t lift {t=MaybeT} or :t lift {m=IO} unfortunately. So go back to two things.
To see order of types you should use some compiler options. Order of type arguments is specified by forall and you can do it manually. Otherwise type parameters will be sorted somehow by the compiler. Mere mortals can't see order of types for lift function but if you're aware of some high-level magic you can:
λ: :set -fprint-explicit-foralls
λ: :t lift
lift
:: forall {t :: (* -> *) -> * -> *} {a} {m :: * -> *}.
(Monad m, MonadTrans t) =>
m a -> t m a
And then you should use #_ to skip some types:
λ: :t lift #MaybeT
lift #MaybeT
:: forall {a} {m :: * -> *}. Monad m => m a -> MaybeT m a
λ: :t lift #_ #IO
lift #_ #IO
:: forall {t :: (* -> *) -> * -> *} {a}.
MonadTrans t =>
IO a -> t IO a
λ: :t lift #_ #_ #Int
lift #_ #_ #Int
:: forall {t :: (* -> *) -> * -> *} {t1 :: * -> *}.
(Monad t1, MonadTrans t) =>
t1 Int -> t t1 Int
Well, this is really mystery for me why m is shown as third argument in forall but should be passed as second but I'm still not aware of all magic.
This is just a hack, but you could always do something like:
:t ap . (id :: ((->) r a) -> ((->) r a))
or
:t \x y -> (id :: ...) (ap x y)
interestingly
Prelude Control.Monad> type Reader = (->) r
Prelude Control.Monad> :t ap . (id :: Reader r a -> Reader r a)
ap . (id :: Reader r a -> Reader r a)
:: Reader r (a -> b) -> (r -> a) -> r -> b
differs from
Prelude Control.Monad> :t \x y -> (id :: Reader r a -> Reader r a) (ap x y)
\x y -> (id :: Reader r a -> Reader r a) (ap x y)
:: (r -> a1 -> a) -> (r -> a1) -> Reader r a
in what ghc recognizes as the synonym Reader r a
It's well known that one way of implementing Haskell typeclasses is via 'typeclass dictionaries'. (This is of course the implementation in ghc, though I make the obligatory remark that Other Implementations are Possible.) To fix ideas, I'll briefly describe how this works. A class declaration like
class (MyClass t) where
test1 :: t -> t -> t
test2 :: t -> String
test3 :: t
can be mechanically transformed into the definition of a datatype like:
data MyClass_ t = MyClass_ {
test1_ :: t -> t -> t,
test2_ :: t -> String,
test3_ :: t,
}
Then we can mechanically transform each instance declaration into an object of that type; for instance:
instance (MyClass Int) where
test1 = (+)
test2 = show
test3 = 3
turns into
instance_MyClass_Int :: MyClass_ Int
instance_MyClass_Int = MyClass_ (+) show 3
and similarly a function which has a typeclass constraint can be turned into a function that takes an extra argument; for instance:
my_function :: (MyClass t) => t -> String
my_function val = test2 . test1 test3
turns into
my_function_ :: MyClass_ t -> t -> String
my_function_ dict val = (test2_ dict) . (test1_ dict) (test3_ dict)
The point is that as long as the compiler knows how to fill in these hidden arguments (which is not totally trivial) then you can translate code that uses classes and instances into code that uses only more basic features of the language.
With that background, here's my question. I have a module M which defines a bunch of classes and functions with class constraints. M is 'opaque'; I can see what it exports (the equivalent of the .hi file) and I can import from it but I can't see its source code. I want to construct a new module N which basically exports the same things but with the transformation above applied. So for instance if M exported
class (Foo t) where
example1 :: t -> t -> t
example2 :: t -- note names and type signatures visible here
-- because they form part of the interface...
instance (Foo String) -- details of implementation invisible
instance (Foo Bool) -- details of implementation invisible
my_fn :: (Foo t) => t -> t -- exported polymorphic fn with class constraint
-- details of implementation invisible
N would start like
module N where
import M
data Foo_ t = Foo_ {example1_ :: t-> t -> t, example2_ :: t}
instance_Foo_String :: Foo_ String
instance_Foo_String = Foo_ example1 example2
instance_Foo_Bool :: Foo_ Bool
instance_Foo_Bool = Foo_ example1 example2
my_fn_ :: Foo_ t -> t -> t
my_fn_ = ???
And my question is what on earth I can put in place of the ???. In other words, what can I write to extract the 'explicit typeclass' version of the function my_fn from the original? It seems rather tricky, and it's infuriating because we all know that 'under the hood' the module M is basically already exporting something like the my_fn_ which I want to create. (Or at least, it is on GHC.)
For the record, I thought I would explain the 'hacky' solution to this which I already know of. I'll basically illustrate it using a series of examples. So let's imagine we're trying to reify the classes, instances and functions in the following (which consists mostly of pretty standard typeclasses, generally simplified somewhat for the exposition):
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
module Src where
import Data.List (intercalate)
class SimpleShow a where
sshow :: a -> String
class SimpleMonoid a where
mempty :: a
mappend :: a -> a -> a
class SimpleFunctor f where
sfmap :: (a -> b) -> f a -> f b
instance SimpleShow Int where
sshow = show
instance SimpleMonoid [a] where
mempty = []
mappend = (++)
instance SimpleMonoid ([a], [b]) where
mempty = ([], [])
mappend (a1, b1) (a2, b2) = (a1 ++ a2, b1 ++ b2)
instance SimpleFunctor [] where
sfmap = map
There's meant to be some generality in these examples: we have
'a' in positive position in the class member
'a' in negative position in the class member
an instance requiring flexible instances
a higher-kinded type
We leave multi-parameter type families as an exercise! Note that I do believe that what I'm presenting is a completely general, syntactic procedure; I just think it's easier to illustrate with examples than by describing the transformation formally. Anyway, let's suppose we've got the following functions to process:
show_2lists :: (SimpleShow a) => [a] -> [a] -> String
show_2lists as1 as2 = "[" ++ intercalate ", " (map sshow as1) ++ "]/["
++ intercalate ", " (map sshow as2) ++ "]"
mconcat :: (SimpleMonoid a) => [a] -> a
mconcat = foldr mappend mempty
example :: (SimpleMonoid (x, y)) => [(x, y)] -> (x, y)
example = foldr mappend mempty
lift_all :: (SimpleFunctor f) => [a -> b] -> [f a -> f b]
lift_all = map sfmap
Then the actual reification looks like:
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleInstances #-}
module Main where
import Unsafe.Coerce
import Src
data Proxy k = Proxy
class Reifies s a | s -> a where
reflect :: proxy s -> a
newtype Magic a r = Magic (forall (s :: *). Reifies s a => Proxy s -> r)
reify :: forall a r. a -> (forall (s :: *). Reifies s a => Proxy s -> r) -> r
reify a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
{-# INLINE reify #-}
data SimpleShow_ a = SimpleShow_ {sshow_ :: a -> String}
data SimpleMonoid_ a = SimpleMonoid_ {mempty_ :: a,
mappend_ :: a -> a -> a}
data SimpleFunctor_ f = SimpleFunctor_ {
sfmap_ :: forall a b. (a -> b) -> (f a -> f b)
}
instance_SimpleShow_Int :: SimpleShow_ Int
instance_SimpleShow_Int = SimpleShow_ sshow
instance_SimpleMonoid_lista :: SimpleMonoid_ [a]
instance_SimpleMonoid_lista = SimpleMonoid_ mempty mappend
instance_SimpleMonoid_listpair :: SimpleMonoid_ ([a], [b])
instance_SimpleMonoid_listpair = SimpleMonoid_ mempty mappend
instance_SimpleFunctor_list :: SimpleFunctor_ []
instance_SimpleFunctor_list = SimpleFunctor_ sfmap
---------------------------------------------------------------------
--code to reify show_2lists :: (SimpleShow a) => [a] -> [a] -> String
-- for each type variable that occurs in the constraints, we must
-- create a newtype. Here there is only one tpye variable ('a') so we
-- create one newtype.
newtype Wrap_a a s = Wrap_a { extract_a :: a }
-- for each constraint, we must create an instance of the
-- corresponding typeclass where the instance variables have been
-- replaced by the newtypes we just made, as follows.
instance Reifies s (SimpleShow_ a) => SimpleShow (Wrap_a a s) where
--sshow :: (Wrap_ a s) -> String
sshow = unsafeCoerce sshow__
where sshow__ :: a -> String
sshow__ = sshow_ $ reflect (undefined :: [] s)
-- now we can reify the main function
show_2lists_ :: forall a. SimpleShow_ a -> [a] -> [a] -> String
show_2lists_ dict = let
magic :: forall s. ([Wrap_a a s] -> [Wrap_a a s] -> String)
-> Proxy s -> ([a] -> [a] -> String)
magic v _ arg1 arg2 = let
w_arg1 :: [Wrap_a a s]
w_arg1 = unsafeCoerce (arg1 :: [a])
w_arg2 :: [Wrap_a a s]
w_arg2 = unsafeCoerce (arg2 :: [a])
w_ans :: String
w_ans = v w_arg1 w_arg2
ans :: String
ans = unsafeCoerce w_ans
in ans
in (reify dict $ magic show_2lists)
---------------------------------------------------------------------
--code to reify mconcat :: (SimpleMonoid a) => [a] -> a
-- Here the newtypes begin with Wrap1 to avoid name collisions with
-- the ones above
newtype Wrap1_a a s = Wrap1_a { extract1_a :: a }
instance Reifies s (SimpleMonoid_ a) => SimpleMonoid (Wrap1_a a s) where
--mappend :: (Wrap1_a a s) -> (Wrap1_a a s) -> (Wrap1_a a s)
mappend = unsafeCoerce mappend__
where mappend__ :: a -> a -> a
mappend__ = (mappend_ $ reflect (undefined :: [] s))
--mempty :: (Wrap1_a a s)
mempty = unsafeCoerce mempty__
where mempty__ :: a
mempty__ = (mempty_ $ reflect (undefined :: [] s))
mconcat_ :: forall a. SimpleMonoid_ a -> [a] -> a
mconcat_ dict = let
magic :: forall s. ([Wrap1_a a s] -> (Wrap1_a a s)) -> Proxy s -> ([a] -> a)
magic v _ arg1 = let
w_arg1 :: [Wrap1_a a s]
w_arg1 = unsafeCoerce (arg1 :: [a])
w_ans :: Wrap1_a a s
w_ans = v w_arg1
ans :: a
ans = unsafeCoerce w_ans
in ans
in (reify dict $ magic mconcat)
---------------------------------------------------------------------
--code to reify example :: (SimpleMonoid (x, y)) => [(x, y)] -> (x, y)
newtype Wrap2_x x s = Wrap2_x { extract2_x :: x }
newtype Wrap2_y y s = Wrap2_y { extract2_y :: y }
instance Reifies s (SimpleMonoid_ (x, y))
=> SimpleMonoid (Wrap2_x x s, Wrap2_y y s) where
--mappend :: (Wrap2_x x s, Wrap2_y y s) -> (Wrap2_x x s, Wrap2_y y s)
-- -> (Wrap2_x x s, Wrap2_y y s)
mappend = unsafeCoerce mappend__
where mappend__ :: (x, y) -> (x, y) -> (x, y)
mappend__ = (mappend_ $ reflect (undefined :: [] s))
--mempty :: (Wrap2_x x s, Wrap2_y y s)
mempty = unsafeCoerce mempty__
where mempty__ :: (x, y)
mempty__ = (mempty_ $ reflect (undefined :: [] s))
example_ :: forall x y. SimpleMonoid_ (x, y) -> [(x, y)] -> (x, y)
example_ dict = let
magic :: forall s. ([(Wrap2_x x s, Wrap2_y y s)] -> (Wrap2_x x s, Wrap2_y y s))
-> Proxy s -> ([(x, y)] -> (x, y))
magic v _ arg1 = let
w_arg1 :: [(Wrap2_x x s, Wrap2_y y s)]
w_arg1 = unsafeCoerce (arg1 :: [(x, y)])
w_ans :: (Wrap2_x x s, Wrap2_y y s)
w_ans = v w_arg1
ans :: a
ans = unsafeCoerce w_ans
in ans
in (reify dict $ magic mconcat)
---------------------------------------------------------------------
--code to reify lift_all :: (SimpleFunctor f) => [a -> b] -> [f a -> f b]
newtype Wrap_f f s d = Wrap_f { extract_fd :: f d}
instance Reifies s (SimpleFunctor_ f) => SimpleFunctor (Wrap_f f s) where
--sfmap :: (a -> b) -> (Wrap_f f s a -> Wrap_f f s b)
sfmap = unsafeCoerce sfmap__
where sfmap__ :: (a -> b) -> (f a -> f b)
sfmap__ = sfmap_ $ reflect (undefined :: [] s)
lift_all_ :: forall a b f. SimpleFunctor_ f -> [a -> b] -> [f a -> f b]
lift_all_ dict = let
magic :: forall s. ([a -> b] -> [Wrap_f f s a -> Wrap_f f s b])
-> Proxy s -> ([a -> b] -> [f a -> f b])
magic v _ arg1 = let
w_arg1 :: [a -> b]
w_arg1 = unsafeCoerce (arg1 :: [a -> b])
w_ans :: [Wrap_f f s a -> Wrap_f f s b]
w_ans = v w_arg1
ans :: [f a -> f b]
ans = unsafeCoerce w_ans
in ans
in (reify dict $ magic lift_all)
main :: IO ()
main = do
print (show_2lists_ instance_SimpleShow_Int [3, 4] [6, 9])
print (mconcat_ instance_SimpleMonoid_lista [[1, 2], [3], [4, 5]])
print (example_ instance_SimpleMonoid_listpair
[([1, 2], ["a", "b"]), ([4], ["q"])])
let fns' :: [[Int] -> [Int]]
fns' = lift_all_ instance_SimpleFunctor_list [\ x -> x+1, \x -> x - 1]
print (map ($ [5, 7]) fns')
{- output:
"[3, 4]/[6, 9]"
[1,2,3,4,5]
([1,2,4],["a","b","q"])
[[6,8],[4,6]]
-}
Note that we use a lot of unsafeCoerce, but always relating two types that differ only in the presence of a newtype. Since the run time representations are identical, this is ok.
What you seem to be asking for is known as "local instances". This would mean that you could write something like:
my_fn_ :: forall t. Foo_ t -> t -> t
my_fn_ fooDict = let instance fooDict :: Foo t
in my_fn
Local instances are a natural extension of type classes. They were even standard in the formalism of Wadler and Blott's paper "How to make ad hoc polymorphism less ad hoc". However, they are problematic because they break a property known as principal types. Additionally, they may also break assumptions that there is only ever a single instance of a certain constraint for a specific type (like e.g. Data.Map's assumption about Ord instances). The first problem could be solved by requiring additional type annotations in a local instance and the latter is related to the controversial "orphan instances", which cause a similar problem.
Another relevant paper is Kiselyov and Shan's "Functional pearl: implicit configurations", which contains a variety of type system tricks to simulate local type instances although it doesn't really apply to your situation (pre-existing type class), IIRC.
This isn't a solution in general, but only for some special cases.
There is a hacky way to do this for class methods of a class C t that have the type parameter t appearing in a negative position in their type. e.g., example1 :: Foo t => t -> t -> t is ok, but not example2 :: Foo t => t.
The trick is to create a wrapper data type Wrapper t which comprises the explicit dictionary methods on t paired with a t value, and which has a Foo instance that exploits the appropriate wrapped dictionary methods, e.g.
data Wrapper x = Wrap {example1__ :: (x -> x -> x), val :: x}
instance Foo (Wrapper x) where
example1 (Wrap example1__ x) (Wrap _ y) = Wrap example1__ (example1__ x y)
my_fn_ :: Foo_ t -> t -> t
my_fn_ (Foo_ example1_ example2_) x = val $ my_fn (Wrap example1_ x)
Something tells me this is probably not the solution you are looking for though- it is not general purpose. In the example here, we cannot do anything with example2 because it has no negative occurrence of t with which to "sneak" functions inside. For your example, this means that my_fn in module M can use only example1.
I would like to programmatically generate random Haskell functions and evaluate them. It seems to me that the only way to do this is to basically generate Haskell code programatically and run it using the GHC API or an external process, returning a string, and parsing it back into a Haskell data type. Is this true?
My reasoning is that as follows. The functions are polymorphic so I can't use Typeable. More importantly, even if I write my own type checker and annotate each function with its type, I can't prove to the Haskell compiler that my type checker is correct. For example, when I pull two functions out of a heterogenous collection of functions and apply one to the other, I need to provide the compiler with a guarantee that the function I'm using to choose these functions only chooses functions with corresponding types. But there is no way to do this, right?
DarkOtter's comment mentions QuickCheck's Arbitrary and CoArbitrary classes, which are certainly the first thing you should try. QuickCheck has this instance:
instance (CoArbitrary a, Arbitrary b) => Arbitrary (a -> b) where ...
As it happens, I was just yesterday reading the QuickCheck code to understand how this works, so I can just share what I learned while it's fresh in my mind. QuickCheck is built around a type that looks like this (and this won't be exactly the same):
type Size = Int
-- | A generator for random values of type #a#.
newtype Gen a =
MkGen { -- | Generate a random #a# using the given randomness source and
-- size.
unGen :: StdGen -> Size -> a
}
class Arbitrary a where
arbitrary :: a -> Gen a
The first trick is that QuickCheck has a function that works like this (and I didn't work out exactly how it's implemented):
-- | Use the given 'Int' to \"perturb\" the generator, i.e., to make a new
-- generator that produces different pseudorandom results than the original.
variant :: Int -> Gen a -> Gen a
Then they use this to implement various instances of this CoArbitrary class:
class CoArbitrary a where
-- | Use the given `a` to perturb some generator.
coarbitrary :: a -> Gen b -> Gen b
-- Example instance: we just treat each 'Bool' value as an 'Int' to perturb with.
instance CoArbitrary Bool where
coarbitrary False = variant 0
coarbitrary True = variant 1
Now with these pieces in place, we want this:
instance (Coarbitrary a, Arbitrary b) => Arbitrary (a -> b) where
arbitrary = ...
I won't write out the implementation, but the idea is this:
Using the CoArbitrary instance of a and the Arbitrary instance of b we can make the function \a -> coarbitrary a arbitrary, which has type a -> Gen b.
Remember that Gen b is a newtype for StdGen -> Size -> b, so the type a -> Gen b is isomorphic to a -> StdGen -> Size -> b.
We can trivially write a function that takes any function of that latter type and switches the argument order around to return a function of type StdGen -> Size -> a -> b.
This rearranged type is isomorphic to Gen (a -> b), so voilà, we pack the rearranged function into a Gen, and we got our random function generator!
I would recommend that you read the source of QuickCheck to see this for yourself. When you tackle that, you're only going to run into two extra details that might slow you down. First, the Haskell RandomGen class has this method:
-- | The split operation allows one to obtain two distinct random generators.
split :: RandomGen g => g -> (g, g)
This operation is used in the Monad instance for Gen, and is rather important. One of the tricks here is that the StdGen is a pure pseudo random number generator; the way Gen (a -> b) works is that for each possible value of a we perturb a b generator, use that perturbed generator to generate the b result, but then we never advance the perturbed generator's state; basically the generated a -> b function is a closure over a pseudo-random seed, and each time we call it with some a we use that specific a to deterministically create a new seed, and then use that to deterministically generate a b that depends on a and the hidden seed.
The abbreviated type Seed -> a -> b more or less sums up what's going on—a pseudo-random function is a rule for generating a b from a pseudo-random seed and an a. This won't work with imperative-style stateful random number generators.
Second: instead of directly having a (a -> StdGen -> Size -> b) -> StdGen -> Size -> a -> b function as I describe above, the QuickCheck code has promote :: Monad m => m (Gen a) -> Gen (m a), which is the generalization of that to any Monad. When m is the function instance of Monad, promote coincides with (a -> Gen b) -> Gen (a -> b), so it's really the same as I sketch above.
Thanks for the very thorough answers above! None of the responses, quite did what I was looking for though. I followed up on DarkOtter's suggestion in the comment the question, and used unsafeCoerce avoid the type checker. The basic idea is that we create a GADT that packages up Haskell functions with their types; the type system I use follows pretty closely Mark P. Jones' "Typing Haskell in Haskell." Whenever I want a collection of Haskell functions, I first coerce them into Any types, then I do what I need to do, stitching them together randomly. When I go to evaluate the new functions, first I coerce them back to the type I wanted. Of course, this isn't safe; if my type checker is wrong or I annotate the haskell functions with incorrect types, then I end up with nonsense.
I've pasted the code I tested this with below. Note that there are two local modules being imported Strappy.Type and Strappy.Utils. The first is the type system mentioned above. The second brings in helpers for the stochastic programs.
Note: in the code below I'm using the combinatory logic as the basic language. That's why my expression language only has application and no variables or lambda abstraction.
{-# Language GADTs, ScopedTypeVariables #-}
import Prelude hiding (flip)
import qualified Data.List as List
import Unsafe.Coerce (unsafeCoerce)
import GHC.Prim
import Control.Monad
import Control.Monad.State
import Control.Monad.Trans
import Control.Monad.Identity
import Control.Monad.Random
import Strappy.Type
import Strappy.Utils (flip)
-- | Helper for turning a Haskell type to Any.
mkAny :: a -> Any
mkAny x = unsafeCoerce x
-- | Main data type. Holds primitive functions (Term), their
-- application (App) and annotations.
data Expr a where
Term :: {eName :: String,
eType :: Type,
eThing :: a} -> Expr a
App :: {eLeft :: (Expr (b -> a)),
eRight :: (Expr b),
eType :: Type} -> Expr a
-- | smart constructor for applications
a <> b = App a b (fst . runIdentity . runTI $ typeOfApp a b)
instance Show (Expr a) where
show Term{eName=s} = s
show App{eLeft=el, eRight=er} = "(" ++ show el ++ " " ++ show er ++ ")"
-- | Return the resulting type of an application. Run's type
-- unification.
typeOfApp :: Monad m => Expr a -> Expr b -> TypeInference m Type
typeOfApp e_left e_right
= do t <- newTVar Star
case mgu (eType e_left) (eType e_right ->- t) of
(Just sub) -> return $ toType (apply sub (eType e_left))
Nothing -> error $ "typeOfApp: cannot unify " ++
show e_left ++ ":: " ++ show (eType e_left)
++ " with " ++
show e_right ++ ":: " ++ show (eType e_right ->- t)
eval :: Expr a -> a
eval Term{eThing=f} = f
eval App{eLeft=el, eRight=er} = (eval el) (eval er)
filterExprsByType :: [Any] -> Type -> TypeInference [] Any
filterExprsByType (e:es) t
= do et <- freshInst (eType (unsafeCoerce e :: Expr a))
let e' = unsafeCoerce e :: Expr a
case mgu et t of
Just sub -> do let eOut = unsafeCoerce e'{eType = apply sub et} :: Any
return eOut `mplus` rest
Nothing -> rest
where rest = filterExprsByType es t
filterExprsByType [] t = lift []
----------------------------------------------------------------------
-- Library of functions
data Library = Library { probOfApp :: Double, -- ^ probability of an expansion
libFunctions :: [Any] }
cInt2Expr :: Int -> Expr Int
-- | Convert numbers to expressions.
cInt2Expr i = Term (show i) tInt i
-- Some basic library entires.
t = mkTVar 0
t1 = mkTVar 1
t2 = mkTVar 2
t3 = mkTVar 3
cI = Term "I" (t ->- t) id
cS = Term "S" (((t2 ->- t1 ->- t) ->- (t2 ->- t1) ->- t2 ->- t)) $ \f g x -> (f x) (g x)
cB = Term "B" ((t1 ->- t) ->- (t2 ->- t1) ->- t2 ->- t) $ \f g x -> f (g x)
cC = Term "C" ((t2 ->- t1 ->- t2 ->- t) ->- t1 ->- t2 ->- t) $ \f g x -> (f x) g x
cTimes :: Expr (Int -> Int -> Int)
cTimes = Term "*" (tInt ->- tInt ->- tInt) (*)
cPlus :: Expr (Int -> Int -> Int)
cPlus = Term "+" (tInt ->- tInt ->- tInt) (+)
cCons = Term ":" (t ->- TAp tList t ->- TAp tList t) (:)
cAppend = Term "++" (TAp tList t ->- TAp tList t ->- TAp tList t) (++)
cHead = Term "head" (TAp tList t ->- t) head
cMap = Term "map" ((t ->- t1) ->- TAp tList t ->- TAp tList t1) map
cEmpty = Term "[]" (TAp tList t) []
cSingle = Term "single" (t ->- TAp tList t) $ \x -> [x]
cRep = Term "rep" (tInt ->- t ->- TAp tList t) $ \n x -> take n (repeat x)
cFoldl = Term "foldl" ((t ->- t1 ->- t) ->- t ->- (TAp tList t1) ->- t) $ List.foldl'
cNums = [cInt2Expr i | i <- [1..10]]
-- A basic library
exprs :: [Any]
exprs = [mkAny cI,
mkAny cS,
mkAny cB,
mkAny cC,
mkAny cTimes,
mkAny cCons,
mkAny cEmpty,
mkAny cAppend,
-- mkAny cHead,
mkAny cMap,
mkAny cFoldl,
mkAny cSingle,
mkAny cRep
]
++ map mkAny cNums
library = Library 0.3 exprs
-- | Initializing a TypeInference monad with a Library. We need to
-- grab all type variables in the library and make sure that the type
-- variable counter in the state of the TypeInference monad is greater
-- that that counter.
initializeTI :: Monad m => Library -> TypeInference m ()
initializeTI Library{libFunctions=es} = do put (i + 1)
return ()
where go n (expr:rest) = let tvs = getTVars (unsafeCoerce expr :: Expr a)
getTVars expr = tv . eType $ expr
m = maximum $ map (readId . tyVarId) tvs
in if null tvs then 0 else go (max n m) rest
go n [] = n
i = go 0 es
----------------------------------------------------------------------
----------------------------------------------------------------------
-- Main functions.
sampleFromExprs :: (MonadPlus m, MonadRandom m) =>
Library -> Type -> TypeInference m (Expr a)
-- | Samples a combinator of type t from a stochastic grammar G.
sampleFromExprs lib#Library{probOfApp=prApp, libFunctions=exprs} tp
= do initializeTI lib
tp' <- freshInst tp
sample tp'
where sample tp = do
shouldExpand <- flip prApp
case shouldExpand of
True -> do t <- newTVar Star
(e_left :: Expr (b -> a)) <- unsafeCoerce $ sample (t ->- tp)
(e_right :: Expr b) <- unsafeCoerce $ sample (fromType (eType e_left))
return $ e_left <> e_right -- return application
False -> do let cs = map fst . runTI $ filterExprsByType exprs tp
guard (not . null $ cs)
i <- getRandomR (0, length cs - 1)
return $ unsafeCoerce (cs !! i)
----------------------------------------------------------------------
----------------------------------------------------------------------
main = replicateM 100 $
do let out = runTI $ do sampleFromExprs library (TAp tList tInt)
x <- catch (liftM (Just . fst) out)
(\_ -> putStrLn "error" >> return Nothing)
case x of
Just y -> putStrLn $ show x ++ " " ++ show (unsafeCoerce (eval y) :: [Int])
Nothing -> putStrLn ""
Would something along these lines meet your needs?
import Control.Monad.Random
randomFunction :: (RandomGen r, Random a, Num a, Floating a) => Rand r (a -> a)
randomFunction = do
(a:b:c:d:_) <- getRandoms
fromList [(\x -> a + b*x, 1), (\x -> a - c*x, 1), (\x -> sin (a*x), 1)]
-- Add more functions as needed
main = do
let f = evalRand randomFunction (mkStdGen 1) :: Double -> Double
putStrLn . show $ f 7.3
EDIT: Building on that idea, we could incorporate functions that have different numbers and types of parameters... as long as we partially apply them so that they all have the same result type.
import Control.Monad.Random
type Value = (Int, Double, String) -- add more as needed
type Function = Value -> String -- or whatever the result type is
f1 :: Int -> Int -> (Int, a, b) -> Int
f1 a b (x, _, _) = a*x + b
f2 :: String -> (a, b, String) -> String
f2 s (_, _, t) = s ++ t
f3 :: Double -> (a, Double, b) -> Double
f3 a (_, x, _) = sin (a*x)
randomFunction :: RandomGen r => Rand r Function
randomFunction = do
(a:b:c:d:_) <- getRandoms -- some integers
(w:x:y:z:_) <- getRandoms -- some floats
n <- getRandomR (0,100)
cs <- getRandoms -- some characters
let s = take n cs
fromList [(show . f1 a b, 1), (show . f2 s, 1), (show . f3 w, 1)]
-- Add more functions as needed
main = do
f <- evalRandIO randomFunction :: IO Function
g <- evalRandIO randomFunction :: IO Function
h <- evalRandIO randomFunction :: IO Function
putStrLn . show $ f (3, 7.3, "hello")
putStrLn . show $ g (3, 7.3, "hello")
putStrLn . show $ h (3, 7.3, "hello")