[Haskell-cafe] Cute code [was: The C Equiv of != in
Haskell miscommunication thread]
Albert Y. C. Lai
trebla at vex.net
Tue May 29 17:56:31 EDT 2007
Vincent Kraeutler wrote:
> Donald Bruce Stewart wrote:
>> P.S. Have some cute code:
>>
>> Control.Monad.Fix.fix ((1:) . scanl (+) 1)
>>
> either way, if one of the Masters Of The Shadow Y Style on this list
> feels like throwing in another koan or two, you'll have at least one
> thankful audience member ;-)
Rewriting in a more beginner form:
s = 1 : scanl (+) 1 s
Recursively defined lists are sometimes hard to predict. Here is a
systematic way of watching what it does. Inspired by a theorem about
fixed points, the following sequence gets closer and closer to the
solution to s = f s:
_|_, f _|_, f (f _|_), f (f (f _|_)), ...
Applying this to our example,
_|_
1 : scanl (+) 1 _|_ = 1:1:_|_
1 : scanl (+) 1 (1:1:_|_) = 1:1:2:3:_|_
1 : scanl (+) 1 (1:1:2:3:_|_) = 1:1:2:3:5:8:_|_
You can continue the process until you run out of patience or you see
the pattern. It is an alternative way to execute the recursion. It is
harder in some cases (e.g., recursive functions) but easier in some
others (e.g., recursive lists).
Executing a program to look for a pattern is the hardest way to
understand it. (Sadly, in most schools it is the only way taught.)
Deriving it from a specification provides more insight, answers the
itching question "so how did you come up with this magic", takes away
the mysticism, teaches more lessons, and moves programming closer to
science-based engineering and further from secret-based guild.
We wish to compute a fibonacci-like sequence s with given s0 and s1, and
s(n+2) = s(n+1) + sn afterwards. We already know a million ways, but
today we add one more. After some exploration, we find
s(n+1) = s1 + (s0 + s1 + s2 + ... + s(n-1))
= scanl (+) s1 s !! n
(This applies to s1 too: scanl (+) s1 s !! 0 = s1.)
Let me abbreviate "scanl (+) s1 s" as "f s". So s(n+1) = f s !! n.
s = [s0, s1, s2, s3, ...]
= [s0, f s !! 0, f s !! 1, f s !! 2, ...]
= s0 : f s
= s0 : scanl (+) s1 s
Now we have it.
More information about the Haskell-Cafe
mailing list