Send Beginners mailing list submissions to
[email protected]
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
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. Re: Re: question about styles of recursion (Brent Yorgey)
2. Re: beginner's type error (Michael Mossey)
3. Re: beginner's type error (Brent Yorgey)
4. Re: beginner's type error (Thomas Davie)
5. Re: beginner's type error (Brent Yorgey)
6. Re: beginner's type error (Brent Yorgey)
7. pattern matching to data inside a list (Michael Mossey)
8. Re: Re: Tutorial/Book with Exercises (Zachary Turner)
----------------------------------------------------------------------
Message: 1
Date: Fri, 27 Mar 2009 08:55:59 -0400
From: Brent Yorgey <[email protected]>
Subject: Re: [Haskell-beginners] Re: question about styles of
recursion
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
On Thu, Mar 26, 2009 at 03:23:01PM -0700, Michael Mossey wrote:
>
> But back to the gist of my question last night: I am aware that most
> examples of recursion presented in the books so far do their processing "as
> the recursion unwinds." In other words:
>
> length :: [a] -> Int
> length [] = 0
> length (x:xs) = 1 + length xs
>
> This function goes deeper and deeper into the recursion before doing any
> calculation, then does all the sums "on the way back out."
Right, this is equivalent to
length = foldr (+) 0
and results in expressions like (1 + (1 + (1 + (1 + ...)))), which
isn't good in this particular case, since none of the additions can be
performed until the very end of the list is reached, and all the sums
are indeed done "on the way back out". There are some cases, however
(such as when the result is some data structure that can be computed
lazily, like another list) when this is exactly what you want.
> Being an imperative programmer, I keep trying to write loops that
> accumulate "on the way down", like this:
>
> length' :: Int -> [a] -> Int
> length' s [] = s
> length' s (x:xs) = length' (s+1) xs
>
> length :: [a] -> Int
> length xs = length' 0 xs
And this is equivalent to
length = foldl (+) 0
and results in expressions like (((((0 + 1) + 1) + 1) + 1) + ... ).
This looks better at first glance, since the sums can start
accumulating as you go. However, since Haskell is lazy, this
particular version is no better, because the sums won't be evaluated
until the result is needed anyway: instead of accumulating a number,
you end up accumulating a giant thunk (unevaluated expression) which
is only evaluated when its result is finally needed, after the call to
length has already finished! So as long as you don't call length on
really long lists, you might as well use your first version---if
you're going to blow the stack on long lists anyway, you might as well
do it in a more natural style. =) But read on...
What we'd like is some way to force the accumulator to be evaluated as
we recurse down the list---and this is exactly what the foldl'
function (from Data.List) does, by introducing a bit of strictness.
So the best way to write length is actually
length = foldl' (+) 0.
Whenever you see this 'accumulator' pattern over lists---some
recursive function which recurses over a list while accumulating some
small summary value---think foldl'.
> I suppose both forms are valid, but the first form seems to be most natural
> in most situations I've encountered in the exercises.
The first is indeed more natural. Generally speaking, if you find
yourself using accumulating parameters, there's probably a simpler way
to do it, or some library function that already does exactly what you
want to do. But it takes experience to learn and recognize such
situations.
-Brent
------------------------------
Message: 2
Date: Fri, 27 Mar 2009 06:01:15 -0700
From: Michael Mossey <[email protected]>
Subject: Re: [Haskell-beginners] beginner's type error
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Peter Verswyvelen wrote:
>
> You can also get rid of the parentheses like this:
>
> thing n = n + fromIntegral $ round $ sqrt n
I'm having a hard time finding an explanation of the dollar signs. What
do they do? It looks like they break up the left-ro-right association of
function names to arguments.
As a beginner, I love how Haskell is filled with so many good ideas, in
many areas. The basic concept of functional programming is good, but
also Haskell has beautiful syntax that's just pleasing to look at, and
also has many convenient features which may not quite qualify as
"beautiful" or "elegant" but are just convenient (still a worthy thing).
Languages that borrow from Haskell, like Python's list comprehensions,
invariably are much dumbed-down implementations. In Python, list
comprehensions don't have guards or pattern matching. (Technically you
can put in a guard via an if statement, but you are doing a lot more
typing at that point.)
Thanks,
Mike
------------------------------
Message: 3
Date: Fri, 27 Mar 2009 09:07:10 -0400
From: Brent Yorgey <[email protected]>
Subject: Re: [Haskell-beginners] beginner's type error
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
On Thu, Mar 26, 2009 at 10:01:07PM +0000, Ivan Moore wrote:
> Hi all,
>
> consider this very small function:
>
> thing n = n + round(sqrt n)
Here's what's going on: since you call sqrt on n, it must have some
type which is an instance of Floating. However, round can return any
type which is an instance of Integral, and since you are adding n to
it, n must have the same type.
This is the takeaway point here: sqrt requires some floating-point
type (like Float or Double), but round returns an Integral type (like
Int or Integer) and n can't be both. In particular you can't call
sqrt on an Integral value. So the fix is to use fromIntegral to
convert:
thing n = n + round (sqrt (fromIntegral n))
>
> It loads into ghci with no warnings.
The reason (which is a bit confusing) is that it typechecks just
fine---if there *were* a type which is an instance of both Integral
and Floating (and I guess round needs RealFrac as well), n could have
that type. There isn't such a type in the standard libraries, but in
theory you could make up your own type which is an instance of both.
> When I try to run "thing 10" I get:
>
> *Main> :load c:\temp\statictype.hs
> [1 of 1] Compiling Main ( C:\temp\statictype.hs, interpreted )
> Ok, modules loaded: Main.
> *Main> thing 10
>
> <interactive>:1:0:
> Ambiguous type variable `t' in the constraints:
> `Integral t' arising from a use of `thing' at <interactive>:1:0-7
> `RealFrac t' arising from a use of `thing' at <interactive>:1:0-7
> `Floating t' arising from a use of `thing' at <interactive>:1:0-7
> Probable fix: add a type signature that fixes these type variable(s)
>
> I have tried to add various type signatures (without really knowing
> what I'm doing!) and haven't been able to get it to work.
>
> I am confused about a few things related to this:
> (a) what type signature fixes it and why it needs any help - it looks
> like the sort of thing that type inference shouldn't need any help
> with
The error message is particularly unhelpful here. Adding a type
signature would only help if you actually had some type which was both
Integral and Floating, but you don't.
> (b) it looks like a runtime type error and I thought you didn't get
> runtime type errors in Haskell
You don't. This isn't a runtime type error; the error was generated
while trying to typecheck the expression 'thing 10' before evaluating
it.
> (c) if I substitute 10 for n and do "10 + round(sqrt 10)" I get the
> expected answer 13
This is because numeric literals (like 10) are polymorphic---they can
have any numeric type. In this case, type inference correctly figures
out that the first 10 should have type Integer, and the second 10
should have type Double. The difference is that they are not
constrained to have the same type---unlike the two occurrences of 'n'
in your original function.
Confusing, isn't it! It's a shame that numeric types can be so
confusing, since that's usually one of the first things that people
run into when learning the language. But I hope this is helpful.
Feel free to ask if you have more questions.
-Brent
------------------------------
Message: 4
Date: Fri, 27 Mar 2009 14:11:03 +0100
From: Thomas Davie <[email protected]>
Subject: Re: [Haskell-beginners] beginner's type error
To: Michael Mossey <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes
On 27 Mar 2009, at 14:01, Michael Mossey wrote:
>
>
> Peter Verswyvelen wrote:
>> You can also get rid of the parentheses like this:
>> thing n = n + fromIntegral $ round $ sqrt n
>
> I'm having a hard time finding an explanation of the dollar signs.
> What do they do? It looks like they break up the left-ro-right
> association of function names to arguments.
You're pretty much there!
The $ function is simply "apply":
f $ a = f a
The difference is that this version of application (as opposed to the
version written as ' ') has very very low precidence, and can be used
to essentially mean "apply this to the whole expression on my right".
Of note though, using chains of ($)s as peter did is commonly
considered bad style, instead, one should use (.) to build up a
function, and then apply it, so not:
fromIntegral $ round $ sqrt n
But instead:
fromIntegral . round . sqrt $ n
Why? Because the latter one has more valid expressions and is
therefor easier to refactor. For example, in the latter one I may
deside that (round . sqrt) is a useful function in itself (lets call
it integralSqrt) and refactor:
fromIntegral . integralSqrt $ n
integralSqrt = round . sqrt
With this style, this is simply a matter of copy/paste.
> As a beginner, I love how Haskell is filled with so many good ideas,
> in many areas. The basic concept of functional programming is good,
> but also Haskell has beautiful syntax that's just pleasing to look
> at, and also has many convenient features which may not quite
> qualify as "beautiful" or "elegant" but are just convenient (still a
> worthy thing).
I'm not sure, most of the convenient things I use in Haskell are also
beautiful and elegant, did you have something in mind?
Thanks
Bob
------------------------------
Message: 5
Date: Fri, 27 Mar 2009 09:11:14 -0400
From: Brent Yorgey <[email protected]>
Subject: Re: [Haskell-beginners] beginner's type error
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
On Fri, Mar 27, 2009 at 06:01:15AM -0700, Michael Mossey wrote:
>
>
> Peter Verswyvelen wrote:
>> You can also get rid of the parentheses like this:
>> thing n = n + fromIntegral $ round $ sqrt n
>
> I'm having a hard time finding an explanation of the dollar signs. What do
> they do? It looks like they break up the left-ro-right association of
> function names to arguments.
($) is just function application. It is defined as:
f $ x = f x
This looks useless, of course, but it also has very low precedence, so
it is often used to avoid parentheses. For example,
(foo bar) (baz t)
can't be written without the parentheses, since that would be parsed
as ((foo bar) baz) t, but it can be written as
foo bar $ baz t
> As a beginner, I love how Haskell is filled with so many good ideas, in
> many areas. The basic concept of functional programming is good, but also
> Haskell has beautiful syntax that's just pleasing to look at, and also has
> many convenient features which may not quite qualify as "beautiful" or
> "elegant" but are just convenient (still a worthy thing).
As a non-beginner, I love this too. So I think you're on to something. =)
-Brent
------------------------------
Message: 6
Date: Fri, 27 Mar 2009 09:17:39 -0400
From: Brent Yorgey <[email protected]>
Subject: Re: [Haskell-beginners] beginner's type error
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
>
> thing n = n + fromIntegral (round (sqrt n))
>
> thing n = n + round (sqrt (fromIntegral n))
Pop quiz for beginners: both of these solve the original problem, but
they are not quite the same. What is the difference? (Do not answer
this question if you are not a beginner!)
-Brent
------------------------------
Message: 7
Date: Fri, 27 Mar 2009 06:25:43 -0700
From: Michael Mossey <[email protected]>
Subject: [Haskell-beginners] pattern matching to data inside a list
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Is there a way to pattern match to a list argument and get a list? For
example, I have this:
-- A LayoutItem has a center position (point), and the four ints are
-- "left width", "rigth width", "top height", and "bottom height"
data LayoutItem = LayoutItem Point Int Int Int Int
deriving Show
-- This computes the left width of a group of composited LayoutItem.
compositeLeftWidth :: [LayoutItem] -> Int
compositeLeftWidth items = let
itemsPosX = [ x | LayoutItem (Point (x,_)) _ _ _ _ <- items ]
itemsLW = [ lw | LayoutItem _ lw _ _ _ <- items ]
z = zipWith (\x y -> x-y+1) itemsPosX itemsLW
in (minimum z) - 1
What I'm wondering is if I could somehow do something like
compositeLeftWidth [ LayoutItem Point( x, _ ) lw _ _ _ ] = ...
and that x and lw would each be the lists I'm calling itemsPosX and
itemsLW above.
Thanks,
Mike
PS Let me repeat my request to find out how to install SOE "on the
library path." I know I'm impatient about this, but it seems simple
enough, and it's driving me crazy that I can only write software in the
same directory where I've installed SOE.
------------------------------
Message: 8
Date: Fri, 27 Mar 2009 08:27:50 -0500
From: Zachary Turner <[email protected]>
Subject: Re: [Haskell-beginners] Re: Tutorial/Book with Exercises
To: Michael Mossey <[email protected]>
Cc: [email protected], Jason White <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset="iso-8859-1"
I haven't actually gotten to this exercise yet, but I feel like this is
probably related: http://www.ece.uc.edu/~franco/C511/html/Scheme/ycomb.html.
I'm not sure if it will give you some pointers in the right direction. It
basically explains how to "abstract out" the recursive part of a function
into a separate function, which is basically what you need.
On Fri, Mar 27, 2009 at 7:21 AM, Michael Mossey <[email protected]>wrote:
>
>
> Jason White wrote:
>
>> Michael Mossey <[email protected]> wrote:
>>
>> YAHT has some hard exercises, early on. He introduces continuations in
>>> chapter 4, briefly, and then casually asks you to rewrite map and filter in
>>> continuation-passing-style. I was stumped.
>>>
>>
>> So am I.
>>
>> Do you have any hints for these, without giving the answers away (I know
>> the
>> answers are in the appendix if I really need them)?
>>
>> Well, I've got some bad news for you. He doesn't include the answers to
> the CPS-related questions. Note: YAHT seems to be incomplete in a number of
> ways, because there are chapter headings that exist only as stubs. However,
> it's a terrific resource, and my thanks to Hal.
>
> I decided to just move on, and I'll come back to continuations when I find
> them in another book.
>
> Mike
>
>
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
http://www.haskell.org/pipermail/beginners/attachments/20090327/824af438/attachment.htm
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 9, Issue 35
****************************************