Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - Declaring the type of multiple functions

I often find myself writing multiple functions with the same type. Let's call this type FuncType. I might write something like this:

funcA :: FuncType
funcB :: FuncType
funcC :: FuncType
funcD :: FuncType

-- Implementations

This feels like a lot of unnecessary typing (typing as in tapping on the keyboard, not declaring types of functions). Is there maybe some way to do this more concisely? What I want would look something along the lines of:

(funcA, funcB, funcC, funcD) :: FuncType

-- Implementations

I really tried to google this but I came up empty. If this isn't a feature of the language, why not? Am I missing something? Am I doing something wrong if I find myself needing this?

like image 314
EFTH Avatar asked Jul 14 '15 18:07

EFTH


2 Answers

Do what you tried without the parentheses.

funcA, funcB, funcC, funcD :: FuncType

In the Haskell 2010 report, you can see in chapter 4 (Declarations and Bindings) that a type signature (gendecl) looks like this:

vars :: [context =>] type

and vars look like this:

var-1 , … , var-n

Which is exactly the form you're looking for.


Sidenote: Haddock will apply a documentation if it finds it around that type signature to every symbol in that (vars) list.

like image 111
MasterMastic Avatar answered Oct 24 '22 08:10

MasterMastic


Alternatively to MasterMastic's answer, you can also actually give the repeated type a name using a type declaration:

-- | why GoodName is a good name
type GoodName = Complicated -> Function -> Type

-- | Foo explanation.
foo :: GoodName
foo = ...

-- | Bar explanation.
bar :: GoodName
bar = ...

This way, you only need to repeat the name instead of the potentially much longer type. Benefits of this style over foo, bar :: Complicated -> Function -> Type include:

  • the named type serves as documentation
  • the named type can be reused elsewhere
  • the function definitions and type signatures are next to each other
  • you can have different haddock comments for the different functions
  • your source code looks more regular
  • if only one of the functions later gets refactored to take additional arguments, the change is more local.

Of course, you can also combine these approaches as foo, bar :: GoodName. Because of type inference, you can usually even leave out the type signature altogether and let the compiler figure out the type.

like image 4
Toxaris Avatar answered Oct 24 '22 09:10

Toxaris