* estimating the complexity of an algorithm: case analysis on any value what-so-ever can require arbitrary computation - so the run time of an algorithm doesn't just depend on the structures you input but also what methods are computing them: combine this with recursion and you've completely lost the ability to say anything meaningful about the algorithms run time.
* memory usage: All of the above applies to memory usage too. It's impossible to write tight programs that run in under a certain level of memory. Therefore you always have to expect a lazy program to crash at any momemnt.
* monads: normal lazy programming is pure, then the time comes when you want to print out values or read in some inputs. At this point you have to rewrite your entire program using monads. Frankly monadic programming implies the programmer doesn't understand continuations. I can undertsand beginner programmers not getting continuations, but language designers? that's just appalling.
* type systems: enforcing a strict type system can help beginner programmers but modern type systems (such as system F variants) will *never* be able to enforce that all your pattern matches are complete, that a program runs safely is a semantic property - syntactic methods like type systems are just conservative approximations of safe programs - so you really are wearing water wings when you use a type system. More generally, it stops you using advanced programming techniques where the type of the objects input and/or returned by a procedure change depending on the circumstances. In the turing tarpit sense, they're right when they say "it's not a limitation" but in terms of pragmatics, it is a huge burden for an advanced programmer.
* infinite streams: every list data type is also an infinite stream type, there's no distinction between finite and infinite. This goes against basic philosophical results and introduces a terrible fuzzyness and implicit assumptions about whether a list is finite or not all over your code. It's completely possible to create infinite streams in strict languages, so lazy programming never gets you anything new. It just make life harder for you.
* efficiency: it's also the case that compilation is much much harder and even on the algorithmic level, programing without state never match up to the efficiency of real programming since all data structures are forced to be persistent, but this just isn't how real computers work. You're denying reality when you program lazy.
* concurrency: programming paradigms come as modules in monadic programming, the result of this is again that you need to rewrite everything if you want to use concurrency. More fundamentally the language itself is hostile to concurrency so it will need a redesign if it wants to be relevant in the future. Who knows when ithe whole language will need to be redesigned from scratch again?
All in all the conclusion is that lazy programming is a fad, a waste of time, just some stupid game people are playing around for a while worse than python. hopefully it will die sooner or later so that more peoples effort isn't wasted on a dead paradigm.
being lazy is good,
sure you lose runtime efficiency,
doesn't require much effort on developer side,
fuck times faster development cycle!
you can get your bloat fuck times faster!
Name:
Anonymous2011-11-06 17:43
Those too lazy to plow in the right season will have no food at the harvest.
It's just a theoretical exercise, like the lambda calculus and Turing machines.
Name:
Anonymous2011-11-06 20:37
Lazy evaluation means only evaluating an expression when its results are needed (note the shift from "reduction" to "evaluation"). So when the evaluation engine sees an expression it builds a thunk data structure containing whatever values are needed to evaluate the expression, plus a pointer to the expression itself. When the result is actually needed the evaluation engine calls the expression and then replaces the thunk with the result for future reference.
Lazy programming is good for high level languages. High level languages aren't going to be much help if you wanted low-level bit-twiddling control. You'll need a thorough understanding of the compilation and run-time system in every language's case to write the most efficient software.
also if you are going to use a high level lang, maybe you are more concerned about expressing succinctly your code than efficiency.
lazy and eager evaluation (at least for me) offer sufficient performance for not to care about it.
Name:
Anonymous2011-11-06 21:26
Lazy programming is good when you you need a possible infinite set or when you need something you want to only exist when you need need it - and not after.
Yes, if you don't program the lazy algorithms yourself you don't know how they'll behave, but surely the same could be said of any other algorithm?
Name:
Anonymous2011-11-07 4:19
Lazy programs are easier to think about while being less easy to read. Haskell is practically lazy CL.
* estimating the complexity of an algorithm: case analysis on any value what-so-ever can require arbitrary computation - so the run time of an algorithm doesn't just depend on the structures you input but also what methods are computing them: combine this with recursion and you've completely lost the ability to say anything meaningful about the algorithms run time.
Wrong. * memory usage: All of the above applies to memory usage too. It's impossible to write tight programs that run in under a certain level of memory. Therefore you always have to expect a lazy program to crash at any momemnt.
Wrong. * monads: normal lazy programming is pure, then the time comes when you want to print out values or read in some inputs. At this point you have to rewrite your entire program using monads. Frankly monadic programming implies the programmer doesn't understand continuations. I can undertsand beginner programmers not getting continuations, but language designers? that's just appalling.
Wrong. * type systems: enforcing a strict type system can help beginner programmers but modern type systems (such as system F variants) will *never* be able to enforce that all your pattern matches are complete, that a program runs safely is a semantic property - syntactic methods like type systems are just conservative approximations of safe programs - so you really are wearing water wings when you use a type system. More generally, it stops you using advanced programming techniques where the type of the objects input and/or returned by a procedure change depending on the circumstances. In the turing tarpit sense, they're right when they say "it's not a limitation" but in terms of pragmatics, it is a huge burden for an advanced programmer.
Wrong. * infinite streams: every list data type is also an infinite stream type, there's no distinction between finite and infinite. This goes against basic philosophical results and introduces a terrible fuzzyness and implicit assumptions about whether a list is finite or not all over your code. It's completely possible to create infinite streams in strict languages, so lazy programming never gets you anything new. It just make life harder for you.
Wrong. * efficiency: it's also the case that compilation is much much harder and even on the algorithmic level, programing without state never match up to the efficiency of real programming since all data structures are forced to be persistent, but this just isn't how real computers work. You're denying reality when you program lazy.
Wrong. * concurrency: programming paradigms come as modules in monadic programming, the result of this is again that you need to rewrite everything if you want to use concurrency. More fundamentally the language itself is hostile to concurrency so it will need a redesign if it wants to be relevant in the future. Who knows when ithe whole language will need to be redesigned from scratch again?
Wrong.
>>22 instance (Show a, Show b) => Show (a,b) where
showsPrec _ (a,b) s = show_tuple [shows a, shows b] s
instance (Show a, Show b, Show c) => Show (a, b, c) where
showsPrec _ (a,b,c) s = show_tuple [shows a, shows b, shows c] s
instance (Show a, Show b, Show c, Show d) => Show (a, b, c, d) where
showsPrec _ (a,b,c,d) s = show_tuple [shows a, shows b, shows c, shows d] s
instance (Show a, Show b, Show c, Show d, Show e) => Show (a, b, c, d, e) where
showsPrec _ (a,b,c,d,e) s = show_tuple [shows a, shows b, shows c, shows d, shows e] s
instance (Show a, Show b, Show c, Show d, Show e, Show f) => Show (a,b,c,d,e,f) where
showsPrec _ (a,b,c,d,e,f) s = show_tuple [shows a, shows b, shows c, shows d, shows e, shows f] s
instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g)
=> Show (a,b,c,d,e,f,g) where
showsPrec _ (a,b,c,d,e,f,g) s
= show_tuple [shows a, shows b, shows c, shows d, shows e, shows f, shows g] s
instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h)
=> Show (a,b,c,d,e,f,g,h) where
showsPrec _ (a,b,c,d,e,f,g,h) s
= show_tuple [shows a, shows b, shows c, shows d, shows e, shows f, shows g, shows h] s
instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h, Show i)
=> Show (a,b,c,d,e,f,g,h,i) where
showsPrec _ (a,b,c,d,e,f,g,h,i) s
= show_tuple [shows a, shows b, shows c, shows d, shows e, shows f, shows g, shows h,
shows i] s
instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h, Show i, Show j)
=> Show (a,b,c,d,e,f,g,h,i,j) where
showsPrec _ (a,b,c,d,e,f,g,h,i,j) s
= show_tuple [shows a, shows b, shows c, shows d, shows e, shows f, shows g, shows h,
shows i, shows j] s
instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h, Show i, Show j, Show k)
=> Show (a,b,c,d,e,f,g,h,i,j,k) where
showsPrec _ (a,b,c,d,e,f,g,h,i,j,k) s
= show_tuple [shows a, shows b, shows c, shows d, shows e, shows f, shows g, shows h,
shows i, shows j, shows k] s
instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h, Show i, Show j, Show k,
Show l)
=> Show (a,b,c,d,e,f,g,h,i,j,k,l) where
showsPrec _ (a,b,c,d,e,f,g,h,i,j,k,l) s
= show_tuple [shows a, shows b, shows c, shows d, shows e, shows f, shows g, shows h,
shows i, shows j, shows k, shows l] s
instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h, Show i, Show j, Show k,
Show l, Show m)
=> Show (a,b,c,d,e,f,g,h,i,j,k,l,m) where
showsPrec _ (a,b,c,d,e,f,g,h,i,j,k,l,m) s
= show_tuple [shows a, shows b, shows c, shows d, shows e, shows f, shows g, shows h,
shows i, shows j, shows k, shows l, shows m] s
instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h, Show i, Show j, Show k,
Show l, Show m, Show n)
=> Show (a,b,c,d,e,f,g,h,i,j,k,l,m,n) where
showsPrec _ (a,b,c,d,e,f,g,h,i,j,k,l,m,n) s
= show_tuple [shows a, shows b, shows c, shows d, shows e, shows f, shows g, shows h,
shows i, shows j, shows k, shows l, shows m, shows n] s
instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h, Show i, Show j, Show k,
Show l, Show m, Show n, Show o)
=> Show (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) where
showsPrec _ (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) s
= show_tuple [shows a, shows b, shows c, shows d, shows e, shows f, shows g, shows h,
shows i, shows j, shows k, shows l, shows m, shows n, shows o] s
show_tuple :: [ShowS] -> ShowS
show_tuple ss = showChar '('
. foldr1 (\s r -> s . showChar ',' . r) ss
. showChar ')'
Name:
Anonymous2011-11-19 13:52
modern type systems will *never* be able to enforce that all your pattern matches are complete
And why not? Isn't it easy to do that if all types have a finite amount of contructors? Doesn't for instance agda's type system do exactly that?