asdf
asdf

Reputation: 38

Show a list of functions in Haskell

Is there a way to show a list of functions in Haskell? When I try

ghci> let functions = [(+), (-), (*)]
ghci> functions

GHCi says:

<interactive>:17:1:
No instance for (Show (Num a0 => a0 -> a0 -> a0))
arising from a use of 'print'
Possible fix:
add an instance declaration for (Show (Num a0 => a0 -> a0 -> a0))
In a stmt of an interactive GHCi command: print it

I'm not sure how to add an instance declaration for this. Any help will be appreciated. Thanks.

Upvotes: 2

Views: 1311

Answers (1)

J. Abrahamson
J. Abrahamson

Reputation: 74344

You can't easily show a function. The standard answer is

instance Show (a -> b) where
  show _ = "<function>"

Prelude> [(+), (-), (*)]
[<function>,<function>,<function>]

Which lets you have a show instance but provides no useful information. This is generally true since there may be no compact way to show the effect of a function. Further, it's worth noting that while it's standard practice to consider functions un-show-able, if you do define that instance you'll be likely to get an overlapping instance condition as any instance like instance (...) => Show (a -> b) is both an orphan and very general. Rule of thumb should be that it's OK in application code, but dangerous in a library.

But with that out of the way, we can make much nicer functions for instance Show (a -> b).

If you know that your function has a bounded input then you can do slightly better

-- | A type instantiates 'Universe' if 'universe' is a 
-- list of every value instantiating the type
class Universe a where
  universe :: [a]

instance Universe Bool where
  universe = [True, False]

instance (Universe a, Show a, Show b) => Show (a -> b) where
  show f = show $ map (\a -> (a, f a)) universe

Prelude> (&&)
[ (True,  [ (True,True)
          , (False,False)
          ])
, (False, [ (True,False)
          , (False,False)
          ])
]

Finally, we can use the Data.Typeable machinery to get a nicer summary show for functions, if that's acceptable.

import Data.Typeable

instance (Typeable a, Typeable b) => Show (a -> b) where
  show f = "{ Function :: " ++ (show $ typeOf f) ++ " }"

Prelude Data.Typeable> [(+), (-), (*)]
[ { Function :: Integer -> Integer -> Integer }
, { Function :: Integer -> Integer -> Integer }
, { Function :: Integer -> Integer -> Integer }
]

But beware that this will fail on polymorphic functions.

Prelude Data.Typeable> ($)

<interactive>:7:1:
    No instance for (Typeable b0) arising from a use of `print'
    The type variable `b0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance [overlap ok] Typeable ()
        -- Defined in `Data.Typeable.Internal'
      instance [overlap ok] Typeable Bool
        -- Defined in `Data.Typeable.Internal'
      instance [overlap ok] Typeable Char
        -- Defined in `Data.Typeable.Internal'
      ...plus 18 others
    In a stmt of an interactive GHCi command: print it

Prelude Data.Typeable> ($) :: (() -> ()) -> () -> ()
{ Function :: (() -> ()) -> () -> () }

Upvotes: 8

Related Questions