Jujhar Singh
Jujhar Singh

Reputation: 129

Passing any type in function signature in Haskell

I want to pass a function a wildcard or any type or even a way to choose between either of multiple types rather than just restrict it to String, or Number, or Boolean, for example:

myFunction :: a -> String

or

myFunction :: _ -> String

or

myFunction :: (String || Number) -> String

Is that possible?

Upvotes: 3

Views: 1825

Answers (3)

rampion
rampion

Reputation: 89053

myFunction :: a -> String means that myFunction can take an argument of any type, but will always return a string. This is legal Haskell syntax.

With PartialTypeSignatures enabled, myFunction :: _ -> String is legal Haskell syntax, with _ acting as a "hole", or a way to get the compiler to tell you what type it inferred at that position:

Temp.hs:4:15: warning: [-Wpartial-type-signatures]
    • Found type wildcard ‘_’ standing for ‘String’
    • In the type signature: myFunction :: _ -> String
  |
4 | myFunction :: _ -> String
  |               ^

If you enable TypeOperators, then you can define type (||) = Either, which make myFuncion :: (String || Number) -> String mean that myFuncion is a function that takes an argument of type Either String Number and returns a String:

type Number = Integer
type (||) = Either

myFuncion = (String ||  Number) -> String
myFuncion (Left string) = string
myFuncion (Right number) = show number

Upvotes: 4

leftaroundabout
leftaroundabout

Reputation: 120711

myFunction :: a -> String is technically possible, however it's profoundly useless – since this must be able to deal with an argument of any type, there's nothing you can actually do with the argument. (It's a bit like getting a can with a completely unspecified substance – you wouldn't eat it in case it's corrosive, you couldn't use it for cleaning purposes in case it's fat, paint or glue, you couldn't process it further... in case of an unrestricted Haskell type you couldn't even analyse it.)

If you narrow it down to types that support some kind of common operation, a polymorphic argument can make sense:

myFunction' :: Show a => a -> String
myFunction' x = "The value is " ++ show x

Your other approach, supporting only two very specific types, is also possible:

myFunction'' :: Either String Integer -> String
myFunction'' (Left s) = "Got a string: “" ++ s ++ "”"
myFunction'' (Right n) = "Got a number: " ++ show n

Note that these two approaches are quite different: Show a => a -> String can be used as String -> String or as Integer -> String, or in fact any other type which supports the show operation (including newly-defined types of your own), but you must decide at compile-time which type you want. At runtime, all arguments passed to this function must then have the same type.

Either String Integer -> String can accept a mixture of String- and Integer values at runtime, but is always restricted to only these two types.

Upvotes: 13

sepp2k
sepp2k

Reputation: 370142

Defining a function a -> String is easily possible, it just won't be able to do anything useful unless you also restrict a to some typeclass (like Show).

_ -> String is not valid syntax. If it were, I imagine it would do the same as a -> String, so you can just use that.

(String || Number) -> String is also not valid syntax, but Either String Number -> String is. You can also define your data type with constructors for the types you want to allow.

Upvotes: 4

Related Questions