Just a quick conceptual question, I am currently trying to learn and understand Haskell better.
I know the Show function is used to convert values to strings, but wh
show
is the function that is defined on functions that are members of the Show
typeclass (if you don't know what a typeclass is, it's kinda like an OOP interface).
By default, functions are not members of the typeclass, so we can't print them.
We could make it a member of the typeclass with
instance Show (a -> b) where
show f = "Unicorns!!"
but here we realize why it isn't implemented by default. There isn't a simple, obvious representation of functions and haskell doesn't want to guess, and thus no instance.
The only "permissible" instance would be one that actually prints out the function, but this would require actual language change, ie it would be hardwired into the compiler, which just isn't worth it for the few cases in which it could be useful.
Further more it's a nontrivial compiler change, Haskell is compiled which means the differences between something like f = g
and
f = g
are entirely lost on it. But you'd definitely want that in your function representation. Because of this, you'd have to lug around this string through out the program. This is definitely not what you want in a binary.
If you really want it to print unicorns!! though, feel free.
It's not that they can't, but that there's not usually a good reason to.
But if you'd like, you definitely can:
Prelude> :{
Prelude| instance Show (a -> b) where
Prelude| show _ = "A function."
Prelude| :}
Prelude> print (\x -> x + 7)
A function.
Prelude> print (\a b c -> a + b + c)
A function.
If you'd like to show
the textual representation of the function, well - you can't do that. Unlike metaprogramming languages like Ruby, JS, etc, Haskell code very little knowledge of its own internals.
There is a partial solution that goes beyond just a fixed string for all functions using Data.Typeable.
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Typeable
instance (Typeable a, Typeable b) => Show (a->b) where
show _ = show $ typeOf (undefined :: a -> b)
in ghci
> let test :: Int->Int; test x = x + x
> test
Int -> Int
Unfortunately without a type signature the type will go to it default.
> let test x = x + x
> test
Integer -> Integer
This solution works on multiple function arities because a -> b -> c
is the same as a -> (b -> c)
which you might as well write as a -> d
where d = b -> c
.
> let m10 a b c d e f g h i j = a * b * c * d * e * f * g * h* i * j
> m10
Integer -> Integer -> Integer -> Integer -> Integer -> Integer -> Integer
-> Integer -> Integer -> Integer -> Integer
This method does not work however when it is unknown if parameters of the function have the typeable class however so while map (+1)
will work map
will not.
> map (+1)
[Integer] -> [Integer]
> map
<interactive>:233:1:
...
After glancing at the internals of Data.Data
and an experiment or two it seems like it could be refactored to be a little more generalized cover more functions.