Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Haskell
Wiki community
Recent changes
Random page
HaskellWiki
Search
Search
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Maintaining laziness
(section)
Page
Discussion
English
Read
Edit
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
View history
General
What links here
Related changes
Special pages
Page information
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==== List construction ==== Be aware that the following two expressions are not equivalent. <haskell> -- less lazy if b then f x else f y -- more lazy f (if b then x else y) </haskell> It is <hask>if undefined then f x else f y</hask> is <hask>undefined</hask>, whereas <hask>f (if b then x else y)</hask> is <hask>f undefined</hask>, which is a difference in [[non-strict semantics]]. Consider e.g. <hask>if b then 'a':x else 'a':y</hask>. It is common source of too much strictness to make decisions too early and thus duplicate code in the decision branches. Intuitively spoken, the bad thing about [[code duplication]] (stylistic questions put aside) is, that the run-time system cannot see that in the branches, some things are equal and do it in common before the critical decision. Actually, the compiler and run-time system could be "improved" to do so, but in order to keep things predictable, they do not do so. Even more, this behaviour is required by theory, since by pushing decisions to the inner of an expression you change the semantics of the expression. So we return to the question, what the programmer actually wants. Now, do you think this expression <haskell> if b then [x] else y:ys </haskell> is maximally lazy? It seems so, but actually it is not. In both branches we create non-empty lists, but the run-time system cannot see this. It is <hask>null (if undefined then [x] else y:ys)</hask> again <hask>undefined</hask>, but we like to have it evaluated to <hask>False</hask>. Here we need lazy pattern matching as provided by <hask>let</hask>. <haskell> let z:zs = if b then [x] else y:ys in z:zs </haskell> This expression always returns the constructor <hask>(:)</hask> and thus <hask>null</hask> knows that the list is not empty. However, this is a little bit unsafe, because the <hask>let z:zs</hask> may fail if in the branches of <hask>if</hask> there is an empty list. This error can only caught at run-time which is bad. We can avoid it using the single constructor pair type. <haskell> let (z,zs) = if b then (x,[]) else (y,ys) in z:zs </haskell> which can be abbreviated to <haskell> uncurry (:) (if b then (x,[]) else (y,ys)) </haskell> Another example is the <hask>inits</hask> function. In the Haskell 98 report the implementation <haskell> inits :: [a] -> [[a]] inits [] = [[]] inits (x:xs) = [[]] ++ map (x:) (inits xs) </haskell> is suggested. However you find that <hask>inits undefined</hask> is undefined, although <hask>inits</hask> always should return the empty list as first element. The following implementation does exactly this: <haskell> inits :: [a] -> [[a]] inits xt = [] : case xt of [] -> [] x:xs -> map (x:) (inits xs) </haskell> See also the article on [[base cases and identities]].
Summary:
Please note that all contributions to HaskellWiki are considered to be released under simple permissive license (see
HaskellWiki:Copyrights
for details). If you don't want your writing to be edited mercilessly and redistributed at will, then don't submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
DO NOT SUBMIT COPYRIGHTED WORK WITHOUT PERMISSION!
Cancel
Editing help
(opens in new window)
Toggle limited content width