Hacker News new | past | comments | ask | show | jobs | submit login

> Is Python the language that comes closest to this goal? And if not, which is?

In the end, it's subjective. And "understandable" and "plain English" may not sit together well, as it can lead to overly verbose code.

But, here's a few examples for you to judge between. (Examples lifted from RosettaCode, which is well worth the look.)

All these languages have claimed, at some time or another, to be easy to read, and close to "plain English". Obviously, this is just a taste.

Python

    def fib(n,x=[0,1]):
       for i in range(abs(n)-1): x=[x[1],sum(x)]
       return x[1]*pow(-1,abs(n)-1) if n<0 else x[1] if n else 0

    for i in range(-30,31): print fib(i),
Ada (A safety-oriented language)

    with Ada.Text_IO, Ada.Command_Line;
    procedure Fib is
        X: Positive := Positive'Value(Ada.Command_Line.Argument(1));

       function Fib(P: Positive) return Positive is
       begin
          if P <= 2 then
             return 1;
          else
             return Fib(P-1) + Fib(P-2);
          end if;
       end Fib;
 
    begin
       Ada.Text_IO.Put("Fibonacci(" & Integer'Image(X) & " ) = ");
       Ada.Text_IO.Put_Line(Integer'Image(Fib(X)));
    end Fib;
AppleScript (Seeing less support from Apple these days, but part of macOS)

    on fib(n)
        if n < 1 then
            0
        else if n < 3 then
            1
        else
            fib(n - 2) + fib(n - 1)
        end if
    end fib
BASIC (Easy to read, easy to use, easy to get lost.)

    FUNCTION itFib (n)
        n1 = 0
        n2 = 1
        FOR k = 1 TO ABS(n)
            sum = n1 + n2
            n1 = n2
            n2 = sum
        NEXT k
        IF n < 0 THEN
            itFib = n1 * ((-1) ^ ((-n) + 1))
        ELSE
            itFib = n1
        END IF
    END FUNCTION
Clojure (A modern Lisp, bits of Scheme, Common Lisp and Java)

    (defn fibs []
      (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))
COBOL, it's so ridiculously verbose, I'm not adding it here. See https://www.rosettacode.org/wiki/Fibonacci_sequence#COBOL

CoffeeScript (Billed as a better JavaScript, it was popular until ES2016)

    fib_rec = (n) ->
      if n < 2 then n else fib_rec(n-1) + fib_rec(n-2)
Delphi (One of my first programming languages. Probably the least verbose staticly typed language without inference I've seen.)

    function FibonacciI(N: Word): UInt64;
    var
      Last, New: UInt64;
      I: Word;
    begin
      if N < 2 then
        Result := N
      else begin
        Last := 0;
        Result := 1;
        for I := 2 to N do
        begin
          New := Last + Result;
          Last := Result;
          Result := New;
        end;
      end;
    end;
 
Elixir (Kinda like Ruby, but running atop Erlang's massively-concurrent VM.)

    defmodule Fibonacci do
        def fib(0), do: 0
        def fib(1), do: 1
        def fib(n), do: fib(0, 1, n-2)
 
        def fib(_, prv, -1), do: prv
        def fib(prvprv, prv, n) do
            next = prv + prvprv
            fib(prv, next, n-1)
        end
    end
 
    IO.inspect Enum.map(0..10, fn i-> Fibonacci.fib(i) end)
Elm (A new language for the web. More a framework that replaces HTML, CSS and JS than just JS.)

    fibonacci : Int -> Int
    fibonacci n = if n < 2 then
            n
        else
            fibonacci(n - 2) + fibonacci(n - 1)
FORTRAN (I've done too much professional work with FORTRAN to like it. It looks straight-forward, but you can do pretty much whatever you feel like with memory, and it'll let you.)

      FUNCTION IFIB(N)
      IF (N.EQ.0) THEN
        ITEMP0=0
      ELSE IF (N.EQ.1) THEN
        ITEMP0=1
      ELSE IF (N.GT.1) THEN
        ITEMP1=0
        ITEMP0=1
        DO 1 I=2,N
          ITEMP2=ITEMP1
          ITEMP1=ITEMP0
          ITEMP0=ITEMP1+ITEMP2
    1   CONTINUE
      ELSE
        ITEMP1=1
        ITEMP0=0
        DO 2 I=-1,N,-1
          ITEMP2=ITEMP1
          ITEMP1=ITEMP0
          ITEMP0=ITEMP2-ITEMP1
    2   CONTINUE
      END IF
      IFIB=ITEMP0
      END
Go (Google's somewhat naive language, can be odd to set up, but is fast, static and fairly readable. Lots of people switch from Python to Go.)

    func fib(a int) int {
      if a < 2 {
        return a
      }
      return fib(a - 1) + fib(a - 2)
    }
Julia (It's a language aimed at scientific application. That means a great number system, a really good compiler, and access to things you usually need FORTRAN for.)

    fib(n) = n < 2 ? n : fib(n-1) + fib(n-2)
Lua (Fast but small. Standard library isn't much bigger than C, but has LuaRocks, a decent package manager, with an active community. Some think of it as a better JavaScript, though it was designed for embedding and has a fantastic C-interop story.)

    function fibs(n) 
      return n < 2 and n or fibs(n - 1) + fibs(n - 2) 
    end
Nim (Think Python, but staticly typed, and much faster.)

    proc Fibonacci(n: int): auto =
      var fn = float64(n)
      var p: float64 = (1.0 + sqrt(5.0)) / 2.0
      var q: float64 = 1.0 / p
          return int64((pow(p, fn) + pow(q, fn)) / sqrt(5.0))



To be fair, here's plain English (from Wikipedia, re-entered by me):

The sequence f(n) of Fibonacci numbers is defined by the recurrence relation:

f(n) = f(n-1) + f(n-2),

with seed values

f(0) = 0 and f(1) = 1

And a possible variant in Python:

    f = [0, 1]
    for i in range(100):
        f.append(f[-1] + f[-2])


heck, if you really want that:

    @functools.lru_cache
    def fibs(n):
        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            return fibs(n-1) + fibs(n-2)
Technically you could also write it as

    def f(n):
        if n in {0, 1}:
            return n
        return f(n-1) + f(n-2)
which is a bit trickier, but arguably better matches the way the seed values are described in english.


What's totally missing from this comparison is that languages allow multiple styles. E.g. the Python variant is for some reason not recursive, and you could write a Python version that looks a lot more like the Go or Lua versions than this Python version. (Which also can be seen as a weakness of Python from a readability point of view: freedom to choose a style also means you can pick the wrong one or a reader can be surprised by more uncommon one)


For the most part, I tried to choose styles that match the language, but yes, just a taste of the languages.

> E.g. the Python variant is for some reason not recursive

Because of the recursion limit in Python, really, as Python doesn't do tail-call elimination. That limit can make recursive code a real pain point, so iterative styles tend to work better.


Where did you find the Nim example? It's by far the strangest fibonacci implementation I have seen (and I am a Nim developer).

Anyway, I translated the Go example to Nim for a better comparison:

    proc fib(a: int): int =
      if a < 2:
        return a
      return fib(a - 1) + fib(a - 2)


Many of these programs do not get tail-call elimination (e.g. I think most languages can not automatically optimize the equivalent of "return f(n-1) + f(n-2)", if they do tail-call elimination at all). The nicest ones do not bother with negative n, some others don't. IMHO not a very useful set of comparisons.


As I mentioned elsewhere, in python the correct way would be to add the @functools.lru_cache decorator. That way you get the caching behavior of the tricky to write methods, with the clarity of the obvious recursive solution.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: