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 Ints, 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 Ints 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.
Show, so they can't be printed for visualization.composeis just a domain-restriction offlip map. (As others have said, the problem is that if you write(+3)into the console you will generate the same error because GHC does not know a canonical way to print the function\x -> x + 3.)composedo not match. In particular: in your example the second argument to compose is(+1), while the second argument ofcomposehas the declared type((u -> t) -> (u -> y)). And(+1)definitely does not have this latter type. You should probably try to first get the type of compose to be what you want it to be.Numand a function fromNumtoNum. As currently written, the type ofcompose [(+2),(+3)] (+1)is(Num (y -> y), Num y) => [y -> y]!!mapping a function over a list of functions is probably not what you want to do.