Signature of a function

Hello! I have a function activityIndicator, which has an argument of class Customer and should return a numeric value. The module is defined as follows. <module-definition> data Purchase = Purchase { price, rebate :: Double } deriving (Show, Eq) data Customer = Customer { id :: Int, purchases :: [Purchase] } activityIndicator :: Customer -> Num activityIndicator (Customer id purchases) = length purchases </module-definition> When I try to load this module into GHCi, I get this error: <error-message> Class `Num' used as a type In the type: Customer -> Num While checking the type signature for `activityIndicator' </error-message> When I remove the line activityIndicator :: Customer -> Num the error disappears. What is wrong in the signature above? TIA Dmitri Pissarenko

Dmitri Pissarenko wrote:
Hello!
I have a function activityIndicator, which has an argument of class Customer and should return a numeric value.
The module is defined as follows.
<module-definition> data Purchase = Purchase { price, rebate :: Double } deriving (Show, Eq)
data Customer = Customer { id :: Int, purchases :: [Purchase] }
activityIndicator :: Customer -> Num activityIndicator (Customer id purchases) = length purchases </module-definition>
What is wrong in the signature above?
'Num' is not a type. It is a type class. You can think of it as a set of types; it includes, for example, Int, Float and the other usual suspects. If you want a type in the class Num the signature looks something like this: Num a => a Which reads like "the type a, where a is in the class Num" However, the problem here is that length returns an Int; so your signature should be: activityIndicator :: Customer -> Int

On 11 Jan 2005, at 14:49, Dmitri Pissarenko wrote:
activityIndicator :: Customer -> Num activityIndicator (Customer id purchases) = length purchases </module-definition>
When I try to load this module into GHCi, I get this error:
Hint: Don't put signatures on functions, then. Instead, let the compiler infer the type for you! If you want to know what the type is, ask GHCi with :info. And if you think it is helpful documentation, you can copy-paste the correct signature from ghci into your source code! There are actually cases when the type inferred will be more general than you want, and in these cases you will want an explicit signature. But that will probably be fairly rare. Jules

Jules,
Hint: Don't put signatures on functions, then. Instead, let the compiler infer the type for you! If you want to know what the type is, ask GHCi with :info. And if you think it is helpful documentation, you can copy-paste the correct signature from ghci into your source code!
Although in this specific case you might be right, I'm not too sure if I agree with you. Especially for newbies, writing signatures upfront can be good practice. First, it lets you think about *what* you are going to write before you actually write it. That way, it really forces structure on the way one codes, and lack of structure is what usually makes learning a new language harder. Second, it gives you a way to test whether what you write is what you intended to write. Although the example is a bit contrived, I recently saw a piece of code written by a relative newbie for selecting the last element of a list: last (x : xs : y) = y If she had written a type signature for this function, the compiler would have flagged this an error. Admittedly, sometimes type signatures can get too intimidating for novice Haskellers. Think about polymorphism and type classes. But, well, one typically gets exposed to polymorphism quite soon, so that should be doable, while it's possible to stay ignorant of type classes for quite some while (if it weren't for those nasty error messages). Just my two cents. Regards, Stefan

On Tue, 11 Jan 2005, Jules Bean wrote:
Hint: Don't put signatures on functions, then. Instead, let the compiler infer the type for you! If you want to know what the type is, ask GHCi with :info. And if you think it is helpful documentation, you can copy-paste the correct signature from ghci into your source code!
There should always be signatures. I had also cases, where the suggested signature was too restricted. I think this was due to the monomorphism restriction.

Am Dienstag, 11. Januar 2005 16:45 schrieb Henning Thielemann:
On Tue, 11 Jan 2005, Jules Bean wrote:
Hint: Don't put signatures on functions, then. Instead, let the compiler infer the type for you! If you want to know what the type is, ask GHCi with :info. And if you think it is helpful documentation, you can copy-paste the correct signature from ghci into your source code!
There should always be signatures.
I do almost unrestrictedly agree! Deciphering code without type signatures is -- except in fairly trivial cases -- always a nuisance, and if the author chose short names instead of telling ones, it is positively disgusting! A type signature usually gives you a quick idea of what's going on even before you read much of the code (though admittedly a type signature f :: a -> a -> a -> b doesn't) and isn't much work to add. Maybe if one is verrrry familiar with the language things are different, but until you reach that familiarity you are grateful for any help. One might replace type signatures with comments, of course, and so convey better information, but that is more work, hence we poor ignorants will settle for signatures. Humbly, Daniel Fischer

Daniel Fischer writes:
One might replace type signatures with comments, of course, and so convey better information, but that is more work, hence we poor ignorants will settle for signatures.
You mean one might add comments _as well as_ type signatures, of course. The only thing worse than no comment is an incorrect comment. At least type signatures are verified by the compiler, and cannot lie. Haddock of course is based entirely on this concept - comments are attached to type signatures, not code. --KW 8-)

On 2005-01-11, Keith Wansbrough
Daniel Fischer writes:
One might replace type signatures with comments, of course, and so convey better information, but that is more work, hence we poor ignorants will settle for signatures.
You mean one might add comments _as well as_ type signatures, of course. The only thing worse than no comment is an incorrect comment. At least type signatures are verified by the compiler, and cannot lie.
Nah, useless comments are also worse than no comments, as they make people think there are useful comments, which prevents useful ones from being written. Better than wrong comments, as it's easier to tell that you should ignore them. -- Aaron Denney -><-

Keith Wansbrough
One might replace type signatures with comments, of course
You mean one might add comments _as well as_ type signatures, of course. The only thing worse than no comment is an incorrect comment.
Personally, I'd be inclined to extend that list to include vague comment, trivial comments, ambigous comments. And if you ever need to comment on *how* a function works, the function is too complex and should be refactored. Spend your time making the code readable instead. (Readable code is more important than correct code -- readable code with bugs can be made correct, with unreadable code you can never be sure of its correctness.) </rant> :-) -kzm -- If I haven't seen further, it is by standing in the footprints of giants

On Tue, Jan 11, 2005 at 05:47:39PM +0100, Daniel Fischer wrote:
One might replace type signatures with comments, of course, and so convey better information, but that is more work, hence we poor ignorants will settle for signatures.
And thinking pessimistically, the comments would be wrong half the time, whereas the signatures are guaranteed by the compiler to be correct. One of the great things about haskell is how expressive the signatures tend to be... although that could just be an illusion due to the fact that I code am now a better coder than I used to be. -- David Roundy http://civet.berkeley.edu/droundy/

On 11 Jan 2005, at 16:47, Daniel Fischer wrote:
Am Dienstag, 11. Januar 2005 16:45 schrieb Henning Thielemann:
On Tue, 11 Jan 2005, Jules Bean wrote:
Hint: Don't put signatures on functions, then. Instead, let the compiler infer the type for you! If you want to know what the type is, ask GHCi with :info. And if you think it is helpful documentation, you can copy-paste the correct signature from ghci into your source code!
There should always be signatures.
I do almost unrestrictedly agree!
Deciphering code without type signatures is -- except in fairly trivial cases -- always a nuisance, and if the author chose short names instead of telling ones, it is positively disgusting!
That's not really what I meant. I meant that, especially when you are figuring out a new language, getting the types inferred for you is helpful and also instructive... I wasn't suggesting that they be left out permanently. Jules

Am Dienstag, 11. Januar 2005 18:45 schrieben Sie:
On 11 Jan 2005, at 16:47, Daniel Fischer wrote:
Am Dienstag, 11. Januar 2005 16:45 schrieb Henning Thielemann:
On Tue, 11 Jan 2005, Jules Bean wrote:
Hint: Don't put signatures on functions, then. Instead, let the compiler infer the type for you! If you want to know what the type is, ask GHCi with :info. And if you think it is helpful documentation, you can copy-paste the correct signature from ghci into your source code!
There should always be signatures.
I do almost unrestrictedly agree!
Deciphering code without type signatures is -- except in fairly trivial cases -- always a nuisance, and if the author chose short names instead of telling ones, it is positively disgusting!
That's not really what I meant.
I meant that, especially when you are figuring out a new language, getting the types inferred for you is helpful and also instructive... I wasn't suggesting that they be left out permanently.
Jules
Sorry about the misunderstanding. Yes, getting the types inferred for you is helpful and instructive, however, as Stefan Holdermans wrote, giving a signature upfront has definite merits, so probably the thing to do is - write a signature first - then comment it out and see what the System infers (and of course try to understand that). Concerning Keith Wansbrough and David Roundy's remarks about wrong comments, I am miserably aware of their correctness, but I still retain the hope that what a comment says about the overall intention of a function is more often helpful than misleading (am I naive?) even if the details lag behind by several updates. Best wishes, Daniel

G'day all.
Quoting Jules Bean
I meant that, especially when you are figuring out a new language, getting the types inferred for you is helpful and also instructive...
I strongly disagree with that. Certainly in Haskell, I found early on that putting in type signatures dramatically improved the quality of my type error messages. Cheers, Andrew Bromage

Inferred types are helpful as a demonstration and exploration tool. Once you are writing programs, having the compiler infer types and check against your requirement is a fantastic bug finder. matt

Same here. I'm usually using explicit type declarations for (at least
all exported) top-level functions.
Michael
On Thu, 13 Jan 2005 14:15:02 +1100, mattr
Inferred types are helpful as a demonstration and exploration tool.
Once you are writing programs, having the compiler infer types and check against your requirement is a fantastic bug finder.
matt
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Hi folks The main thing I like about type signatures is that they help the computer write the boring bits of my programs for me. I've said it before and I'll say it again, no doubt: when we talk about 'type inference', we should distinguish two aspects: (1) the machine doesn't know your plan and tries to guess it (let-rule style, ie finding the abstraction) (2) the machine does know your plan and is fleshing out the details (var-rule style, ie finding the instantiation) You can only make (1) fully automatic at the cost of compulsory ignorance, dumbing down the collection of possible plans to those which are guessable by a machine. I find this unpleasantly restrictive. I at least want a manual override, which Haskell pretty much provides. But as types get more expressive, it's often the case that you can give your programs much more useful types than the machine is ever going to guess. Possibly even a type which explains what a function's output has to do with its input. You can make (2) very powerful indeed. Even in the conventional batch mode of edit-then-compile, you can use overloading to shift the burden of programming from a large amount of tedious plumbing in the program text to a smaller class constraint in the signature. I often find myself using newtypes to explain which structure of my data I want to exploit, then leaving instance inference to exploit it in the 'obvious' way. There are better reasons to write type signatures than that the compiler is too dumb or that the nuns will whip us if we don't. Type signatures enable chunks of program inference, which is much more useful than aspect (1) of type inference. Types can be seen as a highly expressive and compact language of design statements for both humans and machines to read: this design statement determines the space of essential choices for the programmer, and programming can, if we choose, consist of navigating that space. Machines can map that space out for us, and they can fill in all the no-choice bits and pieces once we decide which way to go. I'm not advocating compulsory refinement editing. I'm saying that type signatures currently feel ephemeral only because today's program-construction tools fail to take positive advantage of the fact that machines can manipulate programs in a typed way. Cheers Conor -- http://www.cs.nott.ac.uk/~ctm

Conor McBride wrote:
Types can be seen as a highly expressive and compact language of design statements for both humans and machines to read: this design statement determines the space of essential choices for the programmer, and programming can, if we choose, consist of navigating that space. Machines can map that space out for us, and they can fill in all the no-choice bits and pieces once we decide which way to go.
For me this is the most important aspect. As programs become more complex, and as optimisation techniques are applied (or algorithms changed), Types can act as 'contracts'. Infact I would like to see type expressiveness expanded... Imagine for examle (and this can be done in Haskell with the HList library) adding a static constraint requiring proof at compile time that a list was ordered (according to some criteria: mysort :: (HList a, HOrderedList b) => a -> b Now the definition of the constraint for orderedness is quite simple, and easy to understand (as as it plays no part in the final program efficiency is not an issue) - we are now free to write a heap sort or whatever, knowing it will only compile if it obeys the constraint. Obviously the above only works when the input list is statically determined at compile time... We can easily insert run-time checks in code - but it would be much better to have the compiler proove that the code obeys the criteria under all circumstances. In other words rather than saying for a specific list the result should be ordered, it should be ordered forall a. Keean.
participants (15)
-
Aaron Denney
-
ajb@spamcop.net
-
Conor McBride
-
Daniel Fischer
-
David Roundy
-
Dmitri Pissarenko
-
Henning Thielemann
-
Jules Bean
-
Keean Schupke
-
Keith Wansbrough
-
Ketil Malde
-
mattr
-
Michael Walter
-
robert dockins
-
Stefan Holdermans