Reputation:
compose :: [(u -> t)] -> ((u -> t) -> (u->y)) -> [(u->y)]
compose [] _ = []
compose l f = map f l
Im trying to create a function that receive a list of functions and maps another function over the elements of this lists.
Example: compose [(+2),(+3)] (+1) = [(+3),(+4)]
thats the message the console shows me when i try to run this code
*Main> (compose [(+2)] (+1))
:77:2: No instance for (Show (t0 -> t0)) arising from a use of `print' In a stmt of an interactive GHCi command: print it *Main>
Upvotes: 2
Views: 137
Reputation: 54068
There isn't a way to intelligently convert a function to a string, which is what the error message you see here is saying. There isn't a Show
instance for functions, and you need a Show
instance to see output in GHCi. When you create a function in Haskell the compiler turns it into low level commands, you don't have the original function definition preserved in metadata or anything. You wouldn't be able to see (+1) . (+2)
become (+3)
, it just isn't how Haskell functions work.
Instead you could assign it to a name:
> let fs = compose [(+2)] (+1)
Then apply values to it
> map ($ 10) fs
[13]
If you want to be able to turn something like (+2)
and (+1)
into (+3)
, you'll need to create your own data type. This means that the functions you can represent are severely limited in what they can do unless you define very generic behavior. For simple functions on Int
s, you could do
data ArithFunc
= Add Int
| Subtract Int
| Multiply Int
| ModBy Int
| Abs
| Negate
| Compose ArithFunc ArithFunc
deriving (Eq, Show)
Then you could write a custom compose operator:
toFunction :: ArithFunc -> (Int -> Int)
toFunction (Add x) = (+x)
toFunction (Subtract x) = subtract x
toFunction (Multiply x) = (*x)
toFunction (ModBy x) = (`mod` x)
toFunction Abs = abs
toFunction Negate = negate
toFunction (Compose f1 f2) = toFunction f1 . toFunction f2
infixr 9 #
(#) :: ArithFunc -> ArithFunc -> ArithFunc
f1 # f2 = simplify $ Compose f1 f2
infixr 0 $$
($$) :: ArithFunc -> Int -> Int
f $$ x = toFunction f x
simplify (Compose (Add x) (Add y)) = Add (x + y)
simplify (Compose (Add x) (Subtract y)) = Add (x - y)
-- Continue adding simplification rules as desired
compose :: [ArithFunc] -> (ArithFunc -> ArithFunc) -> [ArithFunc]
compose l f = map (simplify . f) l
Then you could write
> compose [Add 2] (Add 1)
[Add 3]
> map ($$ 10) $ compose [Add 2] (Add 1)
[13]
And this solution is of no where near complete, you would really need to define simplify
in such a way that it continues to simplify nested Compose
constructs until no change was made, there needs to be more rules for simplification, there are other operations that could be represented, resulting in a larger number of simplification rules needed, and more. All of this work above is just to do this sort of thing with a limited set of numeric computations on Int
s only, imagine expanding this to work for all types in general. This is why Haskell chooses a simpler route of storing the function definition less literally, and why you therefore can't show
a function.
Upvotes: 6