user4783821
user4783821

Reputation:

Trying to create a function that maps another function into a function list

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

Answers (1)

bheklilr
bheklilr

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 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.

Upvotes: 6

Related Questions