Send Beginners mailing list submissions to beginners@haskell.org To subscribe or unsubscribe via the World Wide Web, visit http://www.haskell.org/mailman/listinfo/beginners or, via email, send a message with subject or body 'help' to beginners-requ...@haskell.org
You can reach the person managing the list at beginners-ow...@haskell.org When replying, please edit your Subject line so it is more specific than "Re: Contents of Beginners digest..." Today's Topics: 1. Re: Explicit specification of function types (Brandon S. Allbery KF8NH) 2. Re: Explicit specification of function types (Colin Adams) 3. Re: Explicit specification of function types (Felipe Lessa) 4. Re: Explicit specification of function types (Yitzchak Gale) 5. Re: Explicit specification of function types (Tommy M. McGuire) 6. Re: folds again -- myCycle (Will Ness) ---------------------------------------------------------------------- Message: 1 Date: Tue, 24 Mar 2009 00:55:41 -0400 From: "Brandon S. Allbery KF8NH" <allb...@ece.cmu.edu> Subject: Re: [Haskell-beginners] Explicit specification of function types To: Zachary Turner <divisorthe...@gmail.com> Cc: beginners@haskell.org Message-ID: <2ef310c2-8cc3-4795-94ff-42860b474...@ece.cmu.edu> Content-Type: text/plain; charset="us-ascii" Skipped content of type multipart/alternative-------------- next part -------------- A non-text attachment was scrubbed... Name: PGP.sig Type: application/pgp-signature Size: 195 bytes Desc: This is a digitally signed message part Url : http://www.haskell.org/pipermail/beginners/attachments/20090324/b93baf51/PGP-0001.bin ------------------------------ Message: 2 Date: Tue, 24 Mar 2009 07:29:29 +0000 From: Colin Adams <colinpaulad...@googlemail.com> Subject: Re: [Haskell-beginners] Explicit specification of function types To: Zachary Turner <divisorthe...@gmail.com> Cc: beginners@haskell.org Message-ID: <1afdeaec0903240029j9bd9649g939a1ab26a8aa...@mail.gmail.com> Content-Type: text/plain; charset=ISO-8859-1 2009/3/24 Zachary Turner <divisorthe...@gmail.com>: >> 2. Type inference is nice right up until you have to debug a type error; >> then the error gets reported at the point where the compiler realizes it >> can't match up the types, which could be somewhere not obviously related >> (depends on what the call chain looks like). The more concrete types you >> give the compiler, the better (both more complete and more correctly >> located) the type errors will be. > > Regarding the second issue, this occurs in most other type inferring > languages as well, but usually you just specify types up until such time > that your function is fully tested and you deem that it's good, then > removing the type specification. This seems perverse to me. The type signature is very good documentation for other people wanting to use the function. Removing it is a very hostile activity. ------------------------------ Message: 3 Date: Tue, 24 Mar 2009 08:32:34 -0300 From: Felipe Lessa <felipe.le...@gmail.com> Subject: Re: [Haskell-beginners] Explicit specification of function types To: beginners@haskell.org Message-ID: <20090324113234.gb9...@kira.casa> Content-Type: text/plain; charset=us-ascii On Mon, Mar 23, 2009 at 09:02:56PM -0500, Zachary Turner wrote: > Everything I've read has said that it's generally considered good practice > to specify the full type of a function before the definition. Why is this? I've written some reasons not too long ago: http://www.haskell.org/pipermail/beginners/2009-February/001045.html Note that catching errors is probably the most useful benefit of writing type signatures. For a simple example, see > -- f :: Int -> Int > f n = (n * 45 + 10) / 3 Do you see the problem? I've used (/) while I meant `div`. But, suppose you didn't write any type signature at all, the code would compile just fine with type 'f :: Floating a => a -> a'. Now, in another module you say > -- Type signature needed here to select what Read instance you want > getNum :: IO Int > getNum = read `fmap` getLine > -- doF :: IO () > doF = getNum >>= print . f Try it for yourself, what error message you get? The usual cryptic one about "Fractional Int" but *in the definition 'doF'*. Your *programmer mistake* propagated to another *module*. That is a bad, bad thing. Whenever you write type signatures, all these kinds of errors get contained inside the function they were written, saving you a lot of time. The second most important benefit probably would be to help you write the function itself. If you can't write the signature of your function, then you can't write your function at all. And it is not uncommon, even among experienced Haskellers, to write a type signature and then realise they were trying to do something completely wrong! Unfortunately I can't give you any example right now, but believe me. -- Felipe. ------------------------------ Message: 4 Date: Tue, 24 Mar 2009 17:02:04 +0200 From: Yitzchak Gale <g...@sefer.org> Subject: Re: [Haskell-beginners] Explicit specification of function types To: Zachary Turner <divisorthe...@gmail.com>, Michael Mossey <m...@alumni.caltech.edu> Cc: beginners@haskell.org Message-ID: <2608b8a80903240802te1add7bx68d4467c36917...@mail.gmail.com> Content-Type: text/plain; charset=ISO-8859-1 Zachary Turner wrote: >> it's generally considered good practice to specify the >> full type of a function before the definition. Why is this? >> It almost seems to go against the principles of type inference. Michael Mossey wrote: > ...it seems a shame to disregard this power by declaring all types. I concur with the reasons given by previous responders for why it's important to specify type signatures for top-level functions. I'll add that this practice is not at all against the principles of type inference, and you still use its full power: o for auxiliary functions defined in let and where clauses o for functions defined at the interactive prompt o for quick scripting Type inference provides a powerful technique for investigating how to use various tools in Haskell: you use the :type command at the interactive command prompt (or in our IRC channels) to find out what type is assigned to an expression. Besides these direct usages, the compiler makes essential use of type inference whenever you write any non-trivial expression. You may have specified the type of the final result, but the compiler needs to know the type of every intermediate result. This requires type inference because of the very general kinds of polymorphism that Haskell allows. -Yitz ------------------------------ Message: 5 Date: Tue, 24 Mar 2009 12:28:39 -0500 From: "Tommy M. McGuire" <mcgu...@crsr.net> Subject: Re: [Haskell-beginners] Explicit specification of function types To: beginners@haskell.org Message-ID: <49c91847.9010...@crsr.net> Content-Type: text/plain; charset=ISO-8859-1 Zachary Turner wrote: > I'm mostly just trying to understand why it's good in one language, and > bad in another. I'm sure there must be a number of tangible advantages > in each language, that either don't apply or are mapped to disadvantages > in the other. I do not know about F#, but ML requires type signatures at module boundaries. That does limit how far you can get relying on inference alone. Also, the O'Caml community recommends type annotations for documentation purposes although leaving out the annotations is not uncommon for local values. Finally, with "type" synonyms, type inference sometimes results in equivalent typings that are less useful than an annotation (Parsec is the case I remember). -- Tommy M. McGuire mcgu...@crsr.net ------------------------------ Message: 6 Date: Tue, 24 Mar 2009 20:21:33 +0000 (UTC) From: Will Ness <will_...@yahoo.com> Subject: [Haskell-beginners] Re: folds again -- myCycle To: beginners@haskell.org Message-ID: <loom.20090324t194139-...@post.gmane.org> Content-Type: text/plain; charset=utf-8 7stud <bbxx789_05ss <at> yahoo.com> writes: > > Daniel Fischer <daniel.is.fischer <at> web.de> writes: > > Am Donnerstag, 19. März 2009 20:32 schrieb 7stud: > > > Will Ness <will_n48 <at> yahoo.com> writes: > > > > let ws = foldr (:) [1,2,3] ws > > > > > > > > head ws = head (foldr (:) [1,2,3] ws) > > > > = head (foldr (:) [1,2,3] (foldr (:) [1,2,3] ws)) > > > > > > > > because 'ws' is getting matched against (a:as) pattern in foldr > > > > definition, so is immediately needed, causing INFINITE looping. BUT > > > > > > I'm confused by your statement that ws is getting matched against the > > > (a:as) pattern in the foldr definition, and therefore it is immediately > > > > > > evaluated. I didn't think the let expression: > > > > let ws = foldr (:) [1,2,3] ws > > > > > > would cause infinite looping. > > > > Note this is again the left recursive bad definition. As long as we don't want > > to know anything about ws, the definition > > > > ws = foldr (:) [1,2,3] ws > > > > sleeps peacefully. > > .............. > I think you meant to say something like, "to see whether ws is an empty > list and therefore foldr returns [1, 2, 3]: > > foldr (:) [1,2,3] ws > > foldr (:) [1,2,3] [] = [1,2,3] > > we need to know whether ws is empty or not." > > > so we must replace ws in the inner foldr > > with the right hand side of its definition... > > > > > Although, I'm not seeing a pattern match here: > > > >head (x:xs) = x > > ^^^^^^ the pattern > > > >head (foldr (:) [1,2,3] (foldr (:) [1,2,3] ws)) > > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > the expression which is *trying*(?) to be matched against the pattern > > I'll try again, please follow me here. We have these defintions: head (x:xs) = x foldr f z (a:as) = a `f` foldr f z as foldr f z [] = z First, the WRONG DEFINITION: zls = [1,2,3] ws = foldr (:) zls ws Why is it wrong? In Haskell, evaluation is pattern-matching. When the left hand side matches, right hand side IS the answer. That's one step, which gets repeated until we hit some primitive which stops this process. After loading these definitions, if we were to ask the top-level the value of (head ws), what would happen? The system tries to _reduce_ (head ws) ..... look! we have the definition { head (x:xs)=x } , it says to itself. OK, does its LHS (left hand side) match our expression? ----- head ws head (x:xs) ----- Now the system looks to see whether { ws ?= (x:xs) } can be matched. That means checking whether ws is a non-empty list. So the attempt to match 'ws' TRIGGERS the attempt to find out its value, to "reduce" its definition. Now, we have defined it as ws = foldr (:) zls ws Look! we have a definition for 'foldr' with LHS { foldr f z (a:as) }. Does it match our definition, the system asks itself? ----- foldr (:) zls ws foldr f z (a:as) ----- OK, f is (:), z is zls. No problem. WHAT ABOUT { ws ?= (a:as) } ? OOPS, we try to see what's ws's value in order to find out its value. INFINITE LOOP! Not because of any language feature, but because our definition defines itself immediately as itself. That's LEFT recursion. The good, RIGHT recursion, has some intervening case first, so that it'll make sense. Like, what is a natural number? "It's a number!" would be WRONG, LEFT RECURSIVE definition. But saying "It's either 1, or a successor of a natural number" is OK, because we have the terminal clause first ( which gives us an immediate answer, 1). So now, THE RIGHT DEFINITION: zls = [1,2,3] ws = foldr (:) ws zls Here, (head ws) _causes_ the system to check { ws ?= (x:xs) }, so again, its definition is looked into. It's defined in terms of foldr: foldr (:) ws zls -- our definition for 'w' foldr f z (a:as) -- LHS of 'foldr' definiton Do they match? Asks the system. OK, f is (:), z is ws. No problem, both are variables, so we don't need to look inside _their_ values just yet, nothing's forcing us to do that just yet. OK, so what's left is { zls ?= (a:as) }. Aha! No problem again, BECAUSE zls is KNOWN at this point already. So that's OK. Why the two definitions were different? ws = foldr (:) zls ws ws = foldr (:) ws zls Because, foldr is "forcing" in its last argument. Why? Because its definition is { foldr f z (a:as) = ... } so it TRIES TO MATCH ITS LAST ARGUMENT, i.e. it FORCES its value to be found. So we can't put our value that we're defining, into the forcing position of FOLDR call, because that would mean that our value is looked into in order to define its value, BEFORE it is defined. If it were looked into AFTER, there would be no problem. Cheers, ------------------------------ _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners End of Beginners Digest, Vol 9, Issue 29 ****************************************