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. hClose: illegal operation (handle is finalized) and/or
<<loop>> (Travis Erdman)
2. Re: monad nomad gonad gomad (Ertugrul Soeylemez)
3. Re: 2 Questions: mutable data and copying results
(Chadda? Fouch?)
----------------------------------------------------------------------
Message: 1
Date: Tue, 17 Aug 2010 17:06:20 -0700 (PDT)
From: Travis Erdman <[email protected]>
Subject: [Haskell-beginners] hClose: illegal operation (handle is
finalized) and/or <<loop>>
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
> Perhaps in your {BOOLEANS} you are referring to
> 'recurseChildren', which in turn needs the {BOOLEANS}?
Uggh! Indirectly, yes, I am. OK, back to the drawing board for me on this
one. Thanks!
------------------------------
Message: 2
Date: Wed, 18 Aug 2010 02:50:18 +0200
From: Ertugrul Soeylemez <[email protected]>
Subject: [Haskell-beginners] Re: monad nomad gonad gomad
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=US-ASCII
prad <[email protected]> wrote:
> On Sun, 15 Aug 2010 21:11:52 +0200
> Ertugrul Soeylemez <[email protected]> wrote:
>
> > Just remember this: You have an IO computation? You want to refer to
> > its result? Fine, just use '<-'. That's it.
>
> that's what i've been doing the past two days and it works ... except
> in one case.
>
> for example, i have:
>
> ========
> flData <- readFile key
> let (sec:tle:kwd:dsc:url:typ:dat:txt) = lines flData
> ========
>
> so flData is the computation which reads the contents of a file and i
> can take that and do a lines on it. no problem.
I have the impression that you have understood the problem, but you have
yet to realize that you have. Your 'subs' function needs the contents
of a file, so either you pass those contents explicitly or it needs to
become an IO computation, so it can read them itself.
Anyway, honestly I don't understand what your 'subs' function is about.
It seems to interpret stuff after "```", but you can write this a whole
lot simpler and probably more correct, although still very fragile:
subs :: [String] -> [String]
subs [] = []
subs ("```" : code : ts) = gt code : subs ts
subs (t:ts) = t : subs ts
Why is this fragile? Well, try the following:
subs ["```"]
Also do yourself and others a favor and write type annotations at least
for all top level definitions. Yes, Haskell has type inference, but for
important parts of your code you should really write explicit type
annotations.
Reason: First of all, the types of your functions are the specification
of your program. To write a function, the very first thing you should
do is to write its type signature. Never start with the function
definition. Sometimes you write a valid function, which doesn't match
your intended specification. Also given the type signature you can
reason much better about whether your code really does what it should
do, without even compiling it.
Secondly type annotations make your program far more readable. For some
really simple one-liner functions they aren't strictly necessary for
readability, but personally I write them even for the simplest
functions/values.
Now what's the type of your function, when it should read a file? Think
about it for a while. One very easy way is to give it the contents of
the file as a parameter:
subs :: String -> [String] -> [String]
Another reasonable way is to let the function read the file itself:
subs :: FilePath -> [String] -> IO [String]
But beware: The way you were going to do it is very bad. It would read
the file once for each occurence of "```". Better read the file at the
beginning only, at which point you can just as well split this into two
functions:
subs :: String -> [String] -> [String]
subsUsingFile :: FilePath -> [String] -> IO [String]
This particular way to make a nonmonadic functions monadic is called
lifting, and because it is such a common thing to do, there are loads of
combinators to do it, most notably liftM, fmap and (<$>), which are all
the same (though liftM can be used in monads only):
liftM :: Monad m => (a -> b) -> (m a -> m b)
fmap :: Functor f => (a -> b) -> (f a -> f b)
(<$>) :: Functor f => (a -> b) -> (f a -> f b)
The subsUsingFile function can be implemented in one of the following
ways:
-- Raw:
subsUsingFile fn ts = do
content <- readFile fn
return (subs content ts)
-- Using lifting:
subsUsingFile fn ts = liftM (`subs` ts) $ readFile fn
subsUsingFile fn ts = fmap (`subs` ts) $ readFile fn
subsUsingFile fn ts = (`subs` ts) <$> readFile fn
Further note that you are overusing do-notation, even for nonmonadic
code. Read section 6 of my tutorial [1] or a HaskellWiki article about
this [2]. Whenever you see this pattern:
do x <- c
return (f x)
you should consider using lifting:
f <$> c
and don't use do-notation if all you want to do is to make an equation:
let x = y
in ...
especially when your code is not monadic. Your use of the do-notation
in your 'subs' function works only incidentally, because it is indeed a
monadic function, but not in the IO monad, but in the list monad.
[1] http://ertes.de/articles/monads.html#section-9
[2] http://www.haskell.org/haskellwiki/Do_notation_considered_harmful
Greets,
Ertugrul
--
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://ertes.de/
------------------------------
Message: 3
Date: Wed, 18 Aug 2010 11:46:31 +0200
From: Chadda? Fouch? <[email protected]>
Subject: Re: [Haskell-beginners] 2 Questions: mutable data and copying
results
To: C Gosch <[email protected]>
Cc: [email protected]
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=UTF-8
On Tue, Aug 17, 2010 at 4:08 PM, C Gosch <[email protected]> wrote:
>> Since the graph is immutable most of the nodes in the new graph are shared
>> with nodes in the old graph. This is know as path copying and is everywhere
>> persistent ("immutable") data structures are used. Updating a data structure
>> (e.g. a tree) typically requires O(log n) nodes to be copied.
>>
>
> So that means the compiler figures this out for my own data structures, or
> do I have to take care that copying is done this way?
> Sorry for my ignorance, I'm still learning :)
In fact this is not even a case of optimization by the compiler (it
doesn't have to "figure it out") but simply a consequence of the
evaluation model chosen for Haskell. Think of the "delete" function on
list for instance :
> delete _ [] = []
> delete e (x:xs) = if e == x then xs else x : delete e xs
It delete the first occurrence of e in the list. If you follow the
logic of this code, you'll see that the part of the list after the
first occurrence of e will be shared with the result of delete. This
is automatic and apparent in the code since you said "if x == e then
_xs_", in most language you could do the same, but you would then have
to be very cautious since modification of your old list would also
change your new list (and only if you modified the part after the
first "e"), making this a very dangerous function and in practice this
solution wouldn't be proposed by a sane library. In Haskell this
function is perfectly safe since you _can't_ modify the old list, it
is immutable.
When you understand this, you'll see that there's plenty of
interesting data structures that allow manipulations to share the
greatest part of the structure thus allowing to efficiently use
immutable data structure in many more situation than you would have
thought. Chris Okasaki "Purely Functional Data Structure" is an
excellent introduction to this world (where the efficient data
structure may not be the same as in your imperative programs).
--
Jedaï
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 26, Issue 37
*****************************************