Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I agree with Pavel, what is intuitive is subjective. Because I'm (slowly) starting to grok Haskell, I can tell what the Clojure code does, even though I've never written a line of Clojure in my life. So I would consider the Clojure line fairly intuitive, because I've seen it before and I'm adapting to a more functional mindset.</p> <p>Let's consider the mathematical definition, shall we?</p> <pre><code> { 0 if x = 0 } F(x) = { 1 if x = 1 } { F(x - 1) + F(x - 2) if x &gt; 1 } </code></pre> <p>This is less than ideal, formatting wise - those three brackets lined up should be one giant bracket - but who's counting? This is a pretty clear definition of the Fibonacci sequence to most people with a mathematical background. Let's look at the same thing in Haskell, because I know it better than Clojure:</p> <pre><code>fib 0 = 0 fib 1 = 1 fib n = fibs (n - 1) + fibs (n - 2) </code></pre> <p>This is a function, <code>fib</code>, that returns the nth Fibonacci number. Not exactly what we had in Python or Clojure, so let's fix that:</p> <pre><code>fibs = map fib [0..] </code></pre> <p>This makes <code>fibs</code> an infinite list of Fibonacci numbers. <code>fibs !! 1</code> is 1, <code>fibs !! 2</code> is 1, <code>fibs !! 10</code> is 55, and so on. However, this is probably quite inefficient, even in a language that relies on heavily optimized recursion such as Haskell. Let's look at the Clojure definition in Haskell:</p> <pre><code>fibs = 0 : 1 : zipWith (+) fibs (tail fibs) </code></pre> <p>The first couple of characters are pretty simple: <code>0 : 1 :</code> makes a list with elements 0 and 1, and then some more. But what's all the rest of that? Well, <code>fibs</code> is the list we've already got, and <code>tail fibs</code> calls the <code>tail</code> function on our list so far, which returns the list starting at the 2nd element (sort of like in Python saying <code>fibs[1:]</code>). So we take these two lists - <code>fibs</code> and <code>tail fibs</code> - and we zip them together with the <code>+</code> function (operator) - that is, we add the matching elements of each. Let's look:</p> <pre><code>fibs = 0 : 1 : ... tail fibs = 1 : ... zip result = 1 : ... </code></pre> <p>So our next element is 1! But then we add that back onto our <code>fibs</code> list, and look what we get:</p> <pre><code>fibs = 0 : 1 : 1 : ... tail fibs = 1 : 1 : ... zip result = 1 : 2 : ... </code></pre> <p>What we have here is a <em>recursive list definition</em>. As we add more elements to the end of <code>fibs</code> with our <code>zipWith (+) fibs (tail fibs)</code> bit, more elements become avaliable for us to work with when adding elements. Note that Haskell by default is lazy, so just making an infinite list like that won't crash anything (just don't try to print it).</p> <p>So while this is perhaps theoretically the same as our mathematical definition before, it saves the results in our <code>fibs</code> list (sort of an auto-memoization) and we rarely have the problems that might be experienced in a naive solution. For completeness, let's define our <code>fib</code> function in terms of our new <code>fibs</code> list:</p> <pre><code>fib n = fibs !! n </code></pre> <p>If I didn't lose you yet, that's good, because that means you understand the Clojure code. Look:</p> <pre><code>(def fib-seq (lazy-cat [0 1] (map + fib-seq (rest fib-seq)))) </code></pre> <p>We make a list, <code>fib-seq</code>. It starts with two elements, <code>[0 1]</code>, just like our Haskell example. We do a lazy concatenation of these two initial elements with <code>(map + fib-seq (rest fib-seq))</code> - assuming <code>rest</code> does the same thing that <code>tail</code> does in Haskell, we're just combining our list with itself at a lower offset, and then combining these two lists with the <code>+</code> operator/function.</p> <p>After working this through your head a few times, and exploring some other examples, this method of generating fibonacci series becomes at least semi-intuitive. It's at least intuitive enough for me to spot it in a language I don't know.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload