13

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?

1
  • 1
    For short expressions you can write things like [x, y] = [3, 4 :: Int]. Commented Jul 15, 2015 at 7:44

2 Answers 2

18

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.

Sign up to request clarification or add additional context in comments.

2 Comments

REALLY!? Can't believe I tried with parentheses but not without. Maybe this was to obvious for me to find when googling. Either way, THANK YOU!
@EFTH Hehe I feel you :P who hasn't been there. I'm going to update my answer to show it in the language spec. Best of luck!
4

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.

3 Comments

FuncType in the question is (or was at least in my mind when I wrote it) a longer type that has been given a more convenient name with a type declaration. I felt however that having FuncType appear repeatedly in the code still was too much too type. Though, I do agree that this isn't always the best way to go. I often prefer having the type signature right next to the definition, but sometimes that isn't the case.
For clarity, what I wanted in the context of the code you preseneted:foo, bar :: GoodName
I added the foo, bar :: GoodName to the question, and also mentioned type inference. I understand that you're happy with MasterMastic's answer, but I want to chart the design space for future readers.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.