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: Longest common subsequence (Daniel Seidel)
2. Re: Longest common subsequence (Brent Yorgey)
3. folds again -- myCycle (7stud)
4. Re: Integer factorization (Heinrich Apfelmus)
5. Re: folds again -- myCycle (Daniel Fischer)
6. Re: Re: Integer factorization (Francesco Bochicchio)
----------------------------------------------------------------------
Message: 1
Date: Fri, 13 Mar 2009 13:00:17 +0100
From: Daniel Seidel <[email protected]>
Subject: Re: [Haskell-beginners] Longest common subsequence
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=UTF-8; format=flowed
Leslie P. Polzer wrote:
> Hi,
>
> after the factorial function I tried to write my second Haskell
> program, tackling the longest common subsequence algorithm:
>
> lcsList :: [a] -> [a] -> [a]
> lcsList [] _ = []
> lcsList _ [] = []
> lcsList (x:xs) (y:ys) = if x == y
> then lcsList xs ys
> else
> let lcs1 = lcsList x:xs ys
> lcs2 = lcsList xs y:ys
> in if (length lcs1) > (length lcs2)
> then lcs1
> else lcs2
>
> main = do
> putStrLn("Result: " show lcsList [1,2,3] [1,3])
>
> GHC has several problems with it:
>
> lcs.hs:4:27:
> Could not deduce (Eq a) from the context ()
> arising from a use of `==' at lcs.hs:4:27-32
> Possible fix:
> add (Eq a) to the context of the type signature for `lcsList'
>
> I understand that I need to specify that type 'a' needs to
> be a derived type of something that can be compared, but
> how do I specify this in the code?
>
> On a related note, how can I make the function more flexible,
> to discern between case-sensitive and case-insensitive string
> comparison, for example?
>
> In Lisp I would just write this lambda list:
>
> (defun lcs-list (list1 list2 &key (test #'eql))
> ...)
>
> and it would allow me to specify the test but use some sensible
> default if I don't.
>
>
> And two other errors which I don't quite get:
>
> lcs.hs:7:50:
> Couldn't match expected type `[a] -> [[a1] -> [a1]]'
> against inferred type `[a]'
> In the second argument of `(:)', namely `xs ys'
> In the expression: lcsList x : xs ys
> In the definition of `lcs1': lcs1 = lcsList x : xs ys
>
> lcs.hs:8:33:
> Occurs check: cannot construct the infinite type: a = [a]
> When generalising the type(s) for `lcs2'
> In the expression:
> let
> lcs1 = lcsList x : xs ys
> lcs2 = lcsList xs y : ys
> in if (length lcs1) > (length lcs2) then lcs1 else lcs2
>
> in if (length lcs1) > (length lcs2) then lcs1 else lcs2
>
> Can you help me with that?
>
> Thanks,
>
> Leslie
>
>
Hi,
there are some mistakes inside.
a compiling version (not sure, if it does what you expect) is
lcsList :: Eq a => [a] -> [a] -> [a]
lcsList [] _ = []
lcsList _ [] = []
lcsList (x:xs) (y:ys) = if x == y
then x : lcsList xs ys
else
let lcs1 = lcsList (x:xs) ys
lcs2 = lcsList xs (y:ys)
in if (length lcs1) > (length lcs2)
then lcs1
else lcs2
main = do
putStrLn("Result: " ++ show (lcsList [1,2,3] [1,3]))
There were some common mistakes in your version:
1. type signature needs the type class Eq a, to ensure that you can
compare the elements (function (==) is present)
2. function application binds stronger than cons (:), therefore lcsList
x:xs ys means (lcsList x): (xs ys) NOT lcsList (x:xs) ys
3. in the main function concatination of strings (++) and braces around
the argument of show where missing, which leds to
parsing: "Result" as a function with show, lcsList, [1,2,3] and [1,3]
as arguments.
Greetings,
Daniel.
------------------------------
Message: 2
Date: Fri, 13 Mar 2009 09:47:37 -0400
From: Brent Yorgey <[email protected]>
Subject: Re: [Haskell-beginners] Longest common subsequence
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
On Fri, Mar 13, 2009 at 11:58:17AM +0100, Leslie P. Polzer wrote:
>
> On a related note, how can I make the function more flexible,
> to discern between case-sensitive and case-insensitive string
> comparison, for example?
One way you could do this by making a newtype wrapper around Char and
creating a new Eq instance for it, like so:
import Data.Char (toLower)
newtype CaseInsensitive = CI Char
instance Eq CaseInsensitive where
(CI c1) == (CI c2) = toLower c1 == toLower c2
toCI :: String -> [CaseInsensitive]
toCI = map CI
fromCI :: [CaseInsensitive] -> String
fromCI = map (\(CI c) -> c)
-- now to do a case-insensitive LCS search you can just say something like
fromCI (lcsList (toCI "BriCK") (toCI "bARk"))
Of course, you could also write another version of lcsList which takes
an explicit equality predicate, like the lisp version you described,
but there's no way to have 'optional arguments' in Haskell. But this
actually isn't too bad:
-- a generic version
lcsListGen :: (a -> a -> Bool) -> [a] -> [a] -> [a]
lcsListGen eq xs ys = ... LCS algorithm here, using eq for comparison ...
-- the less general version using an Eq constraint can just be
-- implemented in terms of the above, passing in (==) for the equality test.
lcsList :: (Eq a) => [a] -> [a] -> [a]
lcsList = lcsListGen (==)
-Brent
------------------------------
Message: 3
Date: Sat, 14 Mar 2009 07:57:57 +0000 (UTC)
From: 7stud <[email protected]>
Subject: [Haskell-beginners] folds again -- myCycle
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
I spent a long time working on a solution for an exercise in RWH: if you can,
use foldr to mimic haskell's cycle function. At first, I wondered whether
it was even possible. Then I worked on some ideas, and finally I came up with
a solution. Surprisingly, my solution ended up being very simple:
myCycle [] = []
myCycle xs = helperFunc xs [1..]
where helperFunc ys foldrXs = foldr accFunc [] foldrXs
where accFunc _ acc = ys ++ acc
I tested it out, and it worked like a charm:
*Main> let x = myCycle [1, 2, 3]
*Main> take 2 x
[1,2]
*Main> take 10 x
[1,2,3,1,2,3,1,2,3,1]
*Main> take 30 x
[1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3]
After re-examining my solution, I decided that this line:
--where accFunc _ acc = ys ++ acc
read better like this:
--where accFunc _ acc = acc ++ ys
The altered function returns a list just fine. But when I use take on the
list, I get a stack overflow. What is being thunked in both cases?
Thanks.
------------------------------
Message: 4
Date: Sat, 14 Mar 2009 09:39:18 +0100
From: Heinrich Apfelmus <[email protected]>
Subject: [Haskell-beginners] Re: Integer factorization
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1
Colin Paul Adams wrote:
>>>>>> "Heinrich" == Heinrich Apfelmus <[email protected]> writes:
>
> Heinrich> Abstraction is the one driving force for very short
> Heinrich> names. For example, take the definition of foldr
>
> Heinrich> foldr f z [] = z foldr f z (x:xs) = f x (foldr f z
> Heinrich> xs)
>
> Heinrich> Since this function is polymorphic, so f , z and the xs
> Heinrich> can be anything, using more "descriptive" variable names
> Heinrich> is simply not possible; the key point of fold is its
> Heinrich> generality.
>
> Wouldn't unit be a better descriptive name than z?
I have never heard of a unit in relation to fold , I'm afraid. Monoids
and groups have units, as do physicists and a few other mathematical
structures.
While z is indeed quite often the unit of a monoid, for instance in
sum = foldr (+) 0
product = foldr (*) 1
concat = foldr (++) []
it doesn't have to be the unit of a monoid.
Regards,
apfelmus
--
http://apfelmus.nfshost.com
------------------------------
Message: 5
Date: Sat, 14 Mar 2009 11:47:44 +0100
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] folds again -- myCycle
To: 7stud <[email protected]>, [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="iso-8859-1"
Am Samstag, 14. März 2009 08:57 schrieb 7stud:
> I spent a long time working on a solution for an exercise in RWH: if you
> can, use foldr to mimic haskell's cycle function. At first, I wondered
> whether it was even possible. Then I worked on some ideas, and finally I
> came up with a solution. Surprisingly, my solution ended up being very
> simple:
>
> myCycle [] = []
> myCycle xs = helperFunc xs [1..]
> where helperFunc ys foldrXs = foldr accFunc [] foldrXs
> where accFunc _ acc = ys ++ acc
>
> I tested it out, and it worked like a charm:
>
> *Main> let x = myCycle [1, 2, 3]
> *Main> take 2 x
> [1,2]
> *Main> take 10 x
> [1,2,3,1,2,3,1,2,3,1]
> *Main> take 30 x
> [1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3]
>
> After re-examining my solution, I decided that this line:
>
> --where accFunc _ acc = ys ++ acc
>
> read better like this:
>
> --where accFunc _ acc = acc ++ ys
>
> The altered function returns a list just fine. But when I use take on the
> list, I get a stack overflow. What is being thunked in both cases?
Let us rewrite the definition a little (looking only at the case for nonempty
lists):
Variant 1:
myCycle xs = foldr leftAdd [] [1 .. ]
where
leftAdd _ acc = xs ++ acc
foldr leftAdd [] [1 .. ]
~> leftAdd 1 (foldr leftAdd [] [2 .. ])
~> xs ++ (foldr leftAdd [] [2 .. ])
~> xs ++ (leftAdd 2 (foldr leftAdd [] [3 .. ]))
~> xs ++ (xs ++ (foldr leftAdd [] [3 .. ]))
~> xs ++ (xs ++ (xs ++ (xs ++ ...)))
Variant 2:
myCycle xs = foldr rightAdd [] [1 .. ]
where
rightAdd _ acc = acc ++ xs
foldr rightAdd [] [1 .. ]
~> rightAdd 1 (foldr rightAdd [] [2 .. ])
~> (foldr rightAdd [] [2 .. ]) ++ xs
~> (rightAdd 2 (foldr rightAdd [] [3 .. ])) ++ xs
~> ((foldr rightAdd [] [3 .. ]) ++ xs) ++ xs
~> (((... ++ xs) ++ xs) ++ xs
So in the first variant, where the cycled list is added to the front of the
accumulator, the first elements of the list can be accessed before the
accumulator is evaluated.
In the second variant, the front of the result list is the accumulator, so it
has to be evaluated before any part of the result can be accessed.
Unfortunately, the front is an infinite nesting of concatenations, so its
evaluation never finishes.
The thing is that leftAdd is lazy in its second argument, while rightAdd is
strict in it.
If the accumulation function used in foldr is strict in its second argument,
before any part of the result can be accessed, the whole list has to be
traversed (which obviously will never finish for infinite lists).
Let us rewrite it a little more.
Obviously, it doesn't matter which list is passed into
foldr leftAdd []
, as long as it's infinite. So instead of passing [1 .. ], let us pass a
simpler infinite list, say
ones = 1:ones
(or ones = repeat 1).
Then the evaluation becomes
foldr leftAdd [] ones
~> foldr leftAdd [] (1:ones)
~> leftAdd 1 (foldr leftAdd [] ones)
~> xs ++ (foldr leftAdd [] ones)
foldr rightAdd [] ones
~> foldr rightAdd [] (1:ones)
~> rightAdd 1 (foldr rightAdd [] ones)
~> (foldr rightAdd [] ones) ++ xs
So variant 1 amounts to
myCycle xs = let ys = xs ++ ys in ys
and variant 2 to
myCycle2 xs = let ys = ys ++ xs in ys
Now it should be easy to see why the first works, but not the second.
And from the rewriting, we can read off another representation of cycle as a
fold.
We have, for all lists ks, ms:
ks ++ ms = foldr (:) ms ks
So we can write variant 1 as the snappy
myCycle xs = let ys = foldr (:) ys xs in ys
>
> Thanks.
HTH,
Daniel
------------------------------
Message: 6
Date: Sat, 14 Mar 2009 12:21:22 +0100
From: Francesco Bochicchio <[email protected]>
Subject: Re: [Haskell-beginners] Re: Integer factorization
To: [email protected]
Message-ID:
<[email protected]>
Content-Type: text/plain; charset="iso-8859-1"
2009/3/13 Heinrich Apfelmus <[email protected]>
> Francesco Bochicchio wrote:
> > Heinrich Apfelmus wrote:
> >>
> >> Stylistically, one usually uses shorter variable names in Haskell.
> >
> > <beginner rant>
> ...
> > </beginner rant>
> >
> > Rant apart, I notice that in my own excercises I tend to shorten names,
> so
> > maybe there is a reason for that.
> > Nevertheless readability tends to be a big issue in languages used in IT
> > industry, and my feeling is that haskell
> > tends to err on the laconic side of the balance.
>
> The goal is of course to make code readable, that's why I recommend
> short names. :D
>
> Abstraction is the one driving force for very short names. For example,
> take the definition of foldr
>
> foldr f z [] = z
> foldr f z (x:xs) = f x (foldr f z xs)
>
> Since this function is polymorphic, so f , z and the xs can be
> anything, using more "descriptive" variable names is simply not
> possible; the key point of fold is its generality.
Ok but one could still hint at their structure or purpose:
foldr function value (x:xs) = function x ( foldr function value xs )
I believe this would give a little more information to the casual reader.
>
>
> A second, and my main reason for short names, or rather against long
> names, is that names should be to the point. None of the names
>
> newPrimes
> topPrime
> doFactors
> doFilter
>
> accurately describe the object they represent. The primes are not "new",
> the prime is not "on top". The "do" is a prefix does not carry a meaning
> either, it just conveys that doFactors has something to do with
> factors . This is best expressed by making doFactors a local
> definition in the where-block of factors .
I agree that well-documented shared name conventions are better than
roll-your-own.
(x:xs) is one example of such convention, although I tend to adopt slight
variations
like (n:nums) for list of numbers and (ch:chars) for list of characters.
But roll-your-own is still better than cryptic.
>
>
> The name eratosthenesFilter is ok, but since there is no other
> eratosthenes around, no meaning is lost by shortening it to simply
> eratosthenes . Not to mention that the conventional term is "sieve", not
> "filter". The documentation has to elaborate on it anyway.
>
> The generality of the name num hints that a single letter name is
> preferable.
>
> The names that I think are great because they are to the point are
>
> factors
> primes
>
> I have some resistance to use nouns for functions. In the imperative world,
nouns are for
variables, verbs are for functions. I know that in pure functional
programming there is not such a thing
as variables, but still I would reserve nouns for function parameters and
bound expressions. Hence if I have a function that
find factors, I would call it findFactors rather than just factors.
One such example of misnaming - from a beginner point of view - is the
length function in prelude: if it was called
count, I believe more beginners would have realized that works by actually
counting the elements of
a list and not by accessing to some already available 'property' of the
list.
>
>
> > Out of curiosity, there is any reason why you called the auxiliary
> function
> > 'go' ?
>
> Convention. Often, an auxiliary function that does basically the same
> thing as the main function factors but with an extra parameter will be
> named factors' . The apostrophe has the drawback that it's easy to
> forget, so some people now name such auxiliary functions go instead.
>
>
I tend to use _ instead of '. Is more visible and keep conveying the idea
that the auxiliary function
is just a slight variation of the main one.
>
>
> Regards,
> apfelmus
>
Ciao
------
FB
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
http://www.haskell.org/pipermail/beginners/attachments/20090314/c0692edd/attachment.htm
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 9, Issue 15
****************************************