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
****************************************

Reply via email to