Functional Programming
The example of an infinite list of 1s is pretty boring one, since one can implement it in any language like this:
Because Haskell is pure (that is, no mutations) there is no way to tell the difference.
More interesting stuff can be done. Suppose you want an infinite list of squares (my syntax might be off since I don't know Haskell for real):
Now map is AFAIK defined in prelude so I just included it for the fun of it.
Now, squares is an infinite list of squares, that is [1, 4, 9, 16 ... ] continuing as far as you care to look at it.
Also notice how it is possible to avoid explicit conditionals in many cases by relying on pattern matching instead. That is, the version of "map" is selected automatically based on whether second argument is empty or non-empty list.
Ofcourse there's easier way to write that in Haskell, because (AFAIK) you can just as well use so called list-comprehensions:
That basicly says, "let squares be a list of those numbers which you get when you evaluate x*x drawing x from the list of [1, 2, 3 ..]"
Anyway.. the really interesting part of Haskell isn't really that it's lazy or allows list comprehensions, because both of those are pretty easy to implement:
- for lazy evaluation use promises and force them as required, caching values
- for comprehensions, just rewrite then in terms of map and filter (map defined above, filter looking something like:
The really interesting part of Haskell instead, is what the type system does for you....
Code: Select all
struct list_of_int { int x; list_of_int * rest; }
list_of_int ones;
ones.x = 1;
ones.rest = &ones;
More interesting stuff can be done. Suppose you want an infinite list of squares (my syntax might be off since I don't know Haskell for real):
Code: Select all
square x = x * x
ints = [1, 2, 3 .. ]
map fn [] = []
map fn [x:xs] = [fn x : map fn xs]
squares = map square ints
Now, squares is an infinite list of squares, that is [1, 4, 9, 16 ... ] continuing as far as you care to look at it.
Also notice how it is possible to avoid explicit conditionals in many cases by relying on pattern matching instead. That is, the version of "map" is selected automatically based on whether second argument is empty or non-empty list.
Ofcourse there's easier way to write that in Haskell, because (AFAIK) you can just as well use so called list-comprehensions:
Code: Select all
squares = [ x * x | x <- [1, 2, 3 ..]]
Anyway.. the really interesting part of Haskell isn't really that it's lazy or allows list comprehensions, because both of those are pretty easy to implement:
- for lazy evaluation use promises and force them as required, caching values
- for comprehensions, just rewrite then in terms of map and filter (map defined above, filter looking something like:
Code: Select all
filter fn [] = []
filter fn [x:xs] = if fn x
then [x : filter fn xs]
else filter fn xs
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
Also, [..] is a syntax error:
Code: Select all
<ehird> > [1, 2, 3 .. ]
<lambdabot> Parse error
<ehird> > [1]
<lambdabot> [1]
Would it work if one dropped the space?ehird wrote:Also, [..] is a syntax error:
Code: Select all
<ehird> > [1, 2, 3 .. ] <lambdabot> Parse error <ehird> > [1] <lambdabot> [1]
Oh well, I warned about possibly having issues with syntax....
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
Oh ok, I guess [1..] then, that should work, though I'd have preferred something more verbose for readability. Must have confused with some other similar language.
Haskell grammar is evil anyway... one of the things I dislike about the language.
Haskell grammar is evil anyway... one of the things I dislike about the language.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
Code: Select all
[19:43] ehird: > [1..]
[19:43] lambdabot: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,
[19:43] lambdabot: 69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
[19:43] lambdabot: 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,
[19:43] lambdabot: 175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
[19:43] lambdabot: 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,
[19:43] lambdabot: [6 @more lines]
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
the main difference between languages is that some provide features by default that others dont. Lazy evaluation is haskell's feature. Any turing-complete language can be used to build programs with the same behaviour as one haskell program, but it would be tedious. Which is why people use haskell instead
as for actual code:
list_of_ones = repeat 1
list_of_ones = 1:list_of_ones
list_of_ones = f where f = 1 : f
all_ints = [1]++[2]++[3..]
as for actual code:
list_of_ones = repeat 1
list_of_ones = 1:list_of_ones
list_of_ones = f where f = 1 : f
all_ints = [1]++[2]++[3..]