Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do my top level functions need signatures in Haskell?

Tags:

haskell

GHC warns that I don't have the function signatures at the top level. I don't get why I would need them. The problem with providing them is that they are quite sophisticated, like this one (autogenerated):

applyValue :: forall t t1 t2 t3 t4.
                (t2 -> t)
                -> (t2 -> t3 -> t4 -> t1) -> t2 -> t3 -> t4 -> (t -> Bool) -> [t1]

So why would I bother adding them?

the function itself:

applyValue getValueAt stitchAndMove at fabric mark matchAt =
   if matchAt (getValueAt at)
   then [stitchAndMove at fabric mark]
   else []
like image 378
Trident D'Gao Avatar asked Oct 28 '13 03:10

Trident D'Gao


People also ask

What is a function in Haskell?

In Haskell, functions are expressions, just like an integer or a string. Hence, they all have types. In the example, we see that “func” is a function that takes two arguments, an Int and a String, and returns a list of Strings. We can apply a function by giving it arguments. Function application changes the type of an expression.

What is Haskell’s type system?

In functional programming, our code actually consists of expressions to be evaluated. Under Haskell’s type system, every expression has a type. Luckily, unlike C++ and Java, Haskell’s most widely used compiler (GHC) is generally quite good at type inference. It can usually determine the type of every expression in our code.

What are the types of expressions in Haskell?

Every expression in Haskell has a type, including functions and if statements The compiler can usually infer the types of expressions, but you should generally write out the type signature for top level functions and expressions.

Why does my package signature require a function not defined by module?

If you do all that, but GHC complains that the signature requires a function/type which is not defined by the module, this means that the implementing module doesn't implement enough functionality to support the requirements of the package in question. You might be able to extend module with the missing functionality, see #FAQ.


1 Answers

  • As a form of machine-checkable documentation. If you believe that type to be the right type, putting it there asks the compiler to double-check that you didn't hose your own interface during your later inevitable refactoring sessions.
  • As human-readable documentation. Although as you observe, when you notice you're writing an awful machine-generated type, it's probably time to think about what (type-level) abstractions you need to make it human-readable.
  • For haddock. Haddock comments get attached to type signatures, not bindings, so if you leave out a type signature, your carefully hand-written documentation will be silently ignored.
  • To improve error messages and ghci query results: although the actual names of type variables don't matter, GHC tries hard to preserve names when they're provided by the user. Something like (node -> Bool) -> (edge -> Bool) -> (graph -> Bool) can be much more readable than (t1 -> Bool) -> (t2 -> Bool) -> (t3 -> Bool), even though they're equivalent.
like image 97
Daniel Wagner Avatar answered Sep 17 '22 00:09

Daniel Wagner