Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

printing a list of type signatures

Tags:

types

haskell

I want to be able to type the following in ghci:

map showTypeSignature [(+),(-),show]

I want ghci to return the following list of Strings:

["(+) :: Num a => a -> a -> a","(-) :: Num a => a -> a -> a","show :: Show a => a -> String"]

Naturally, the first place that I run into trouble is that I cannot construct the first list, as the type signatures of the functions don't match. What can I do to construct such a list? How does ghci accomplish the printing of type signatures? Where is the ghci command :t defined (its source)?

like image 763
renick Avatar asked Mar 12 '14 06:03

renick


3 Answers

What you're asking for isn't really possible. You cannot easily determine the type signature of a Haskell term from within Haskell. At run-time, there's hardly any type information available. The GHCi command :t is a GHCi command, not an interpreted Haskell function, for a reason.

To do something that comes close to what you want you'll have to use GHC itself, as a library. GHC offers the GHC API for such purposes. But then you'll not be able to use arbitrary Haskell terms, but will have to start with a String representation of your terms. Also, invoking the compiler at run-time will necessarily produce an IO output.

like image 98
kosmikus Avatar answered Nov 17 '22 11:11

kosmikus


kosmikus is right, this doesn't really work out. And shouldn't, the static type system is one of Haskell's most distinguishing features!

However, you can emulate this for monomorphic functions quite well using the Dynamic existential:

showTypeSignature :: Dynamic -> String
showTypeSignature = show . dynTypeRep

Prelude Data.Dynamic> map showTypeSignature [toDyn (+), toDyn (-), toDyn (show)]
["Integer -> Integer -> Integer","Integer -> Integer -> Integer","() -> [Char]"]

As you see ghci had to boil the functions down to monomorphic type here for this to work, which particularly for show is patently useless.

like image 7
leftaroundabout Avatar answered Nov 17 '22 11:11

leftaroundabout


The answers you have about why you can't do this are very good, but there may be another option. If you don't care about getting a Haskell list, and just want to see the types of a bunch of things, you can define a custom GHCi command, say :ts, that shows you the types of a list of things; to wit,

Prelude> :ts (+) (-) show
(+) :: Num a => a -> a -> a
(-) :: Num a => a -> a -> a
show :: Show a => a -> String

To do this, we use :def; :def NAME EXPR, where NAME is an identifier and EXPR is a Haskell expression of type String -> IO String, defines the GHCi command :NAME. Running :NAME ARGS evaluates EXPR ARGS to produce a string, and then runs the resulting string in GHCi. This is less confusing than it sounds. Here's what we do:

Prelude> :def ts return . unlines . map (":type " ++) . words
Prelude> :ts (+) (-) show
(+) :: Num a => a -> a -> a
(-) :: Num a => a -> a -> a
show :: Show a => a -> String

What's going on? This defines :ts to evaluate return . unlines . map (":t " ++) . words, which does the following:

  • words: Takes a string and splits it on whitespace; e.g., "(+) (-) show" becomes ["(+)", "(-)", "show"].
  • map (":type " ++): Takes each of the words from before and prepends ":type "; e.g., ["(+)", "(-)", "show"] becomes [":type (+)", ":type (-)", ":type show"]. Notice that we now have a list of GHCi commands.
  • unlines: Takes a list of strings and puts newlines after each one; e.g., [":type (+)", ":type (-)", ":type show"] becomes ":type (+)\n:type (-)\n:type show\n". Notice that if we pasted this string into GHCi, it would produce the type signatures we want.
  • return: Lifts a String to an IO String, because that's the type we need.

Thus, :ts name₁ name₂ ... nameₙ will evaluate :type name₁, :type name₂, …, :type nameₙ in succession and prints out the results. Again, you can't get a real list this way, but if you just want to see the types, this will work.

like image 2
Antal Spector-Zabusky Avatar answered Nov 17 '22 11:11

Antal Spector-Zabusky