Write Genric function that takes function signature of varying length of argument as argument in type level - haskell

I want to create a function, that takes function as varying argument, the only thing i know about the funtion argument(which is a function itself) is they are wrapped in the same Monad....
myFunc :: forall arguments output m.
MonadEffect m
=> (arguments -> m output)
-> m (argument -> m output)
myFunc fn = do
-- getting function's name using FFI and other stuff...
pure fn
I'm able to write the function, when I explicitly specify the argument length like,
-- for function with ONE argument
myFunc1 :: forall argument1 output m
. MonadEffect m
=> (argument1 -> m output)
-> m (argument1 -> m output)
myFunc1 fn = do
-- do something
pure fn
-- for function with TWO argument
myFunc2 :: forall argument1 argument2 output m.
MonadEffect m =>
(argument1 -> argument2 -> m output) ->
m (argument1 -> argument2 -> m output)
myFunc2 fn = do
-- do something
pure fn
How can I write argument1 -> argument2 -> m output as argument -> m output in type level?
is there any type/Constraint that helps in doing so?
ps: I just want to understand whether it's possible

In Haskell, you can define type families that calculate the return type of a function:
type family Result f where
Result (a -> b) = Result b
Result b = b
and a type-level list of the types of its arguments (in reverse order):
type Arguments f = Arguments' '[] f
type family Arguments' args f where
Arguments' args (a -> b) = Arguments' (a ': args) b
Arguments' args b = args
This would allow you to write:
myFunc :: forall f arguments output m.
( Monad m
, Result f ~ m output
, Arguments f ~ arguments
) => f -> m f
myFunc fn = pure fn
which would make available type variables output and arguments within the body of your function:
myFunc :: forall f arguments output m.
( MonadIO m
, Result f ~ m output
, Arguments f ~ arguments
, Typeable arguments, Typeable output
) => f -> m f
myFunc fn = do
liftIO . putStrLn $ "Result: " ++ show (typeRep (Proxy #output))
liftIO . putStrLn $ "Arguments: " ++ show (typeRep (Proxy #arguments))
pure fn
This may or may not be suitable for what you're trying to do, and it may or may not work in Purescript.
Anyway, here's a self-contained Haskell example:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
import Control.Monad.IO.Class
import Data.Typeable
type family Result f where
Result (a -> b) = Result b
Result b = b
type Arguments f = Arguments' '[] f
type family Arguments' args f where
Arguments' args (a -> b) = Arguments' (a ': args) b
Arguments' args b = args
myFunc :: forall f arguments output m.
( MonadIO m
, Result f ~ m output
, Arguments f ~ arguments
, Typeable arguments, Typeable output
) => f -> m f
myFunc fn = do
liftIO . putStrLn $ "Result: " ++ show (typeRep (Proxy #output))
liftIO . putStrLn $ "Arguments: " ++ show (typeRep (Proxy #arguments))
liftIO . putStrLn $ ""
pure fn
resultType :: forall f r. (Result f ~ r, Typeable r) => f -> String
resultType _ = show $ typeRep (Proxy #r)
main :: IO ()
main = do
_ <- myFunc (pure . length :: String -> IO Int)
_ <- myFunc ((\x y -> pure (x+y)) :: Double -> Double -> IO Double)
putStrLn "done"

Related

How to pattern match on Proxy?

I need a method to conditionally apply a function depending on the specific instance of a class.
I tried using Proxy to annotate the function with the type of its input:
class ApplyIf b where
applyIf :: Show b => proxy a -> (a -> a) -> b -> String
instance ApplyIf Int where
applyIf (p :: Proxy Int) f b = show (f b)
applyIf _ _ b = show b
instance ApplyIf String where
applyIf _ _ b = show b
main = do
putStrLn $ applyIf (Proxy:: Proxy Int) (*2) 1 -- 2
putStrLn $ applyIf (Proxy:: Proxy Int) (*2) "ok" -- ok
But I get an 'Illegal type signature: 'Proxy Int' error on line 5.
Should I use some other mechanisms, like Tagged, Typeable, ... ?
Do you mean something like this?
import Data.Typeable
applyIf :: (Show a, Typeable a, Show b, Typeable b) => (b -> b) -> a -> String
applyIf f x = case cast x of
Nothing -> show x
Just y -> show (f y)
main = do
putStrLn $ applyIf ((*2) :: Int -> Int) (1 :: Int)
putStrLn $ applyIf ((*2) :: Int -> Int) "ok"
Here we use Typeable to check at runtime whether a and b are the same type, which either lets us apply f or not.
Proxy is a type that holds no data, but has a phantom parameter of arbitrary type (or even kind).
I.e. at runtime you can't tell if you have a Proxy Int and so can't pattern match on this. Instead of Proxy you need TypeRep:
{-# LANGUAGE TypeApplications #-}
import Type.Reflection
class ApplyIf a where
applyIf :: Show b => TypeRep a -> (a -> a) -> b -> String
instance ApplyIf Int where
applyIf tr f b | tr == typeRep #Int = show (f b)
| otherwise = show b
(you need TypeApplications for #Int). You could use typeOf (0 :: Int) as well.
EDIT: would this do what you want? See Data.Type.Equality.
{-# LANGUAGE TypeApplications #-}
import Type.Reflection
import Data.Type.Equality
-- could have Typeable a constraint instead of a TypeRep a param
applyIf :: (Show b, Show c, Typeable b) => TypeRep a -> (a -> c) -> b -> String
applyIf tr f b =
case testEquality tr (typeOf b) of
Just Refl -> show (f b)
Nothing -> show b
main = do
putStrLn $ applyIf (typeRep #Int) (*2) 1 -- 2
putStrLn $ applyIf (typeRep #Int) (*2) "ok" -- ok

haskell - chain up elements with an associative binary operation

I am an intermediate schemer, but only a haskell beginner. Here is my problem:
Suppose you have an associative binary operation, says (>>=). Is there a polyvariadic function p such that p (>>=) h g f e = h >>= g >>= f >>= e?
I am asking this question because this question says it is possible if the binary operation takes inputs of the same type. I wonder if this can be generalized.
EDIT-1: I try to modify the code in http://okmij.org/ftp/Haskell/vararg-fn.lhs (the section of Variable number of variably typed arguments) with little progress.
EDIT-2: Simplify the code a bit.
{-# LANGUAGE FunctionalDependencies, FlexibleInstances #-}
module Main where
class Lfold f a b | b -> a where
lfold :: (a -> (f a) -> (f a)) -> (f a) -> a -> b
instance Lfold f a (f a) where
lfold op rid x = op x rid
instance Lfold f a b => Lfold f a (a -> b) where
lfold op rid x y = lfold op (op x rid) y
test :: [String]
test = lfold (:) [] "a" "b" "c"
main :: IO ()
main = putStrLn $ show test
Yes, you can create such a function. It is very ugly however, and you will need to explicitly type every argument you are going to pass to make the compiler find the correct instance.
Starting from the polyvariadic function template you linked, I arrived at
{-# LANGUAGE FlexibleInstances, InstanceSigs, MultiParamTypeClasses #-}
class ImplicitChain m a r where
p :: m a -> r
instance Monad m => ImplicitChain m a (m a) where
p :: m a -> m a
p x = x
instance (Monad m, ImplicitChain m b r) => ImplicitChain m a ((a -> m b) -> r) where
p :: m a -> (a -> m b) -> r
p x f = p (x >>= f)
h :: Int -> [Int]
h = replicate 2
g :: Int -> [Int]
g = (:[])
f :: Int -> [Int]
f = flip enumFromTo 2
test :: [Int]
test = p [1::Int] h g f
But you were asking whether we can do more generic, so that the binary operation is an argument as well. Yes:
{-# LANGUAGE FlexibleInstances, InstanceSigs, MultiParamTypeClasses, UndecidableInstances #-}
class ImplicitVariadic a b r where
p :: (a -> b -> a) -> r
instance ImplicitVariadic a b (a -> a) where
p :: (a -> b -> a) -> a -> a
p _ x = x
instance (ImplicitVariadic a b (a -> r)) => ImplicitVariadic a b (a -> b -> r) where
p :: (a -> b -> a) -> a -> b -> r
p f x y = p f (f x y)
You can't (at least, not easily), because you need to know how many arguments you are getting ahead of time. Because all functions in Haskell are automatically curried, every function takes exactly one argument and returns one value. Even a simple binary operator takes one argument (the first operand) and returns a function that takes one argument (the second operand) and returns a result. That is,
a + b == (+) a b
== ((+) a) b
There is no way for your imaginary function p to know from its first argument how many other arguments are going to be given. That is, what should the type of p be?
p :: (a -> a -> a) -> a -- zero arguments?
p :: (a -> a -> a) -> a -> a -- one argument?
p :: (a -> a -> a) -> a -> a -> a -- two arguments?
p :: (a -> a -> a) -> a -> a -> a -> a -- three arguments?
Instead, the best you can do is use a fold, which takes an operation and a list of operands.
foldr (+) 0 [h, g, f, e] == h + g + f + e + 0 -- explicit first argument of 0
foldr1 (+) [h, g, f, e] == h + g + f + e -- assumes a list of at least one value
To see what I mean by "not easily", look at the implementation of printf in the Text.Printf module. Even that is not a good example, because the first argument carries information (the number of placeholders in the format string) that a binary operation alone does not.

Can I have a polymorphic function argument that may not need to be supplied for some types?

I have a datatype F with a special-case for Int:
{-# LANGUAGE GADTs, RankNTypes #-}
data F a where
FGen :: a -> F a
FInt :: F Int
Without exposing the details of this datatype to callers - the real datatype is more complicated containing internal implementation details - I want to provide an API for using it:
transform :: (a -> b) -> b -> F a -> b
transform f i (FGen v) = f v
transform f i FInt = i
If I'm going to call transform on a F Int, clearly both of the first two arguments are important:
transformInt :: F Int -> Int
transformInt = transform (+1) 5
But if I'm going to call it on a F Char, the second argument is unnecessary as the value can't be a FInt:
transformChar :: F Char -> Char
transformChar = transform id (error "unreachable code")
Is there a way I can express this in the type of transform?
I tried
transform :: (a -> b) -> (a ~ Int => b) -> F a -> b
transform f i (FGen v) = f v
transform f i FInt = i
but then transformChar doesn't compile with
Couldn't match type ‘Char’ with ‘Int’
Inaccessible code in
a type expected by the context: (Char ~ Int) => Char
In the second argument of ‘transform’, namely
‘(error "unreachable code")’
In the expression: transform id (error "unreachable code")
In an equation for ‘transformChar’:
transformChar = transform id (error "unreachable code")
and anyway I'd still want absurd value I could use instead of the error to properly express that the compiler should be able to prove the code will never be used.
We can use the propositional equality type in Data.Type.Equality and we can also express inaccessibility of code from GHC 7.8, using empty case expressions:
{-# LANGUAGE GADTs, RankNTypes, EmptyCase, TypeOperators #-}
import Data.Type.Equality
data F a where
FGen :: a -> F a
FInt :: F Int
transform :: (a -> b) -> ((a :~: Int) -> b) -> F a -> b
transform f i (FGen v) = f v
transform f i FInt = i Refl
transformChar :: F Char -> Char
transformChar = transform id (\p -> case p of {})
-- or (\case {}) with LambdaCase
transformInt :: F Int -> Int
transformInt = transform (+1) (const 5)
I like the answer with a GADT for the type equality proof better. This answer explains how to do the same thing with TypeFamilies. With closed type families we can write functions from types to the unit () and zero Void of the type system to represent prepositional truth and false.
{-# LANGUAGE TypeFamilies #-}
import Data.Void
type family IsInt a where
IsInt Int = ()
IsInt a = Void
The second argument to transform is () -> b when IsInt a and Void -> b (the type of absurd) when a isn't an integer.
transform :: (a -> b) -> (IsInt a -> b) -> F a -> b
transform f i (FGen v) = f v
transform f i FInt = i ()
transformChar can be written in terms of absurd and transformInt must pass in b as a constant function.
transformChar :: F Char -> Char
transformChar = transform id absurd
transformInt :: F Int -> Int
transformInt = transform (+1) (const 5)
More Reusable
At András Kovács suggestion, we can make this more reusable with a type family for type equality (==) that returns lifted Bools.
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
type family (==) a b :: Bool where
(==) a a = True
(==) a b = False
We could provide another type family to convert True to () and False to Void. For this specific problem it reads better to go all the way from True or False and some type b to () -> b or Void -> b.
type family When p b where
When True b = () -> b
When False b = Void -> b
The type of transform then reads.
transform :: (a -> b) -> When (a == Int) b -> F a -> b

Transform a function with a typeclass constraint into a function taking an explicit typeclass dictionary

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.

Haskell printf arguments as array

I want to call Text.Printf function printf with array but I can't find a way.
Here are two not working versions (actually same idea).
import Text.Printf
printfa :: (PrintfArg a) => String -> [a] -> String
printfa format args = step (printf format) args
where
step :: (PrintfType r, PrintfArg a) => r -> [a] -> r
step res (x:[]) = res x
step res (x:xs) = step (res x) xs
printfa' :: (PrintfArg a) => String -> [a] -> String
printfa' format args = foldr (\arg p -> p arg) (printf format) args
main = putStrLn $ printfa "%s %s" ["Hello", "World"]
GHC errors are:
printfa.hs:8:23:
Couldn't match type `r' with `a1 -> r'
`r' is a rigid type variable bound by
the type signature for
step :: (PrintfType r, PrintfArg a1) => r -> [a1] -> r
at printfa.hs:8:5
The function `res' is applied to one argument,
but its type `r' has none
In the expression: res x
In an equation for `step': step res (x : []) = res x
printfa.hs:12:41:
The function `p' is applied to one argument,
but its type `String' has none
In the expression: p arg
In the first argument of `foldr', namely `(\ arg p -> p arg)'
In the expression: foldr (\ arg p -> p arg) (printf format) args
(Why: I'm writing DSL and want to provide printf function.)
First, realize that PrintfArg a => [a] is not a heterogenous list. That is, even though Int and String are both instances of PrintfArg, [ 1 :: Int, "foo" ] is not a valid construct.
So if you did define a function :: PrintfArg a => String -> [a] -> String, that all the args would be constrained to be of the same type.
To get around this, you can use existential quantification.
{-# LANGUAGE ExistentialQuantification #-}
import Text.Printf
data PrintfArgT = forall a. PrintfArg a => P a
printfa :: PrintfType t => String -> [ PrintfArgT ] -> t
printfa format = printfa' format . reverse
where printfa' :: PrintfType t => String -> [ PrintfArgT ] -> t
printfa' format [] = printf format
printfa' format (P a:as) = printfa' format as a
main = do
printfa "hello world\n" []
printfa "%s %s\n" [ P "two", P "strings"]
printfa "%d %d %d\n" (map P $ [1 :: Int, 2, 3])
printfa "%d %s\n" [ P (1 :: Int), P "is the loneliest number" ]
The reason your first solution didn't work is because you passed res to step as an argument.
When you have foo :: Constraint a => a -> t you guarantee that foo will work on all instances of Constraint. And though there exists an instance of PrintfType which can take an argument, not all instances can. Thus your compiler error.
In contrast, when you have foo :: Constraint a => t -> a, you guarantee that foo will return any desired instance of Constraint. Again, the caller gets to choose which instance. This is why my code works - when printfa' recurses, it requires the recursive call to return a value from the (PrintfArg a, PrintfType t) => a -> t instance.
For your second try, the compiler complains because foldr requires that the accumulated value be of the same type between iterations. GHC notices that the accumulated value must be a function type (PrintfArg a, PrintfType t) => a -> t, because you apply it in the iterated function. But you return the applied value, which it can figure out is of type t. This means that t equals a -> t, which GHC doesn't like, because it doesn't allow infinite types. So it complains.
If you want to use a fold, you can, you just have to mask the accumulator type using Rank2Types or RankNTypes to keep the type constant between iterations.
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-}
import Text.Printf
data PrintfArgT = forall a. PrintfArg a => P a
data PrintfTypeT = T { unT :: forall r. PrintfType r => r }
printfa :: PrintfType t => String -> [ PrintfArgT ] -> t
printfa format = unT . foldl (\(T r) (P a) -> T $ r a ) (T $ printf format)
I'm not sure this is a minimal solution, but if you know the length of your vectors statically you can use type-indexed Vectors and type indexed Fun types.
{-# LANGUAGE GADTs, TypeFamilies #-}
import Text.Printf
data Z
data S n
data Vec n a where
Nil :: Vec Z a
Cons :: a -> Vec n a -> Vec (S n) a
type family Fn n b a
type instance Fn Z b a = a
type instance Fn (S n) b a = b -> Fn n b a
-- in order to tell the compiler that we want to consider a function as a `Fn`
newtype Fun n b a = Fun (Fn n b a)
run :: Fun n b a -> Vec n b -> a
run (Fun f) v = case v of
Nil -> f
Cons b more -> run (Fun $ f b) more
z :: Vec (S (S Z)) String
z = Cons "foo" (Cons "bar" Nil)
then you can do run (Fun $ printf "%s %s") z.
Here is mine.
import Text.Printf (printf, PrintfType)
printfList_ :: PrintfType t => String -> [String] -> Int -> t
printfList_ string list n | n == 0 = printf string (list !! 0)
| otherwise = (printfList_ string list (n - 1)) (list !! n)
printfList :: String -> [String] -> String
printfList string list = (printfList_ string list (length list - 1)) :: String
Example:
> printfList "%s%s%s" ["a","b","c"]
"abc"

Resources