4 ms·
Am I the only one having a hard time reading lisp? Non-functional programs read like plain English. Particularly Python but I just can't get my head around the
by borplk 14y ago
Am I the only one having a hard time reading lisp?
Non-functional programs read like plain English. Particularly Python but I just can't get my head around the functional ones.
- loup-vaillant 14y agoImperative programs read like English. Functional ones read like Apache. The Main difference is, a functional programs mainly talks about what things are, not what they do. For instance: // C(++) int square(int n) { return n * n; } -- Haskell square :: Int -> Int square n = n * n The C code reads like a procedure to follow: "return n times n to whoever called you" (I'm anthropomorphising square(), here). The Haskell code reads like a description: "the square of n is n times n". That was the first major difficulty. Now the second one: functional code is often like reversed imperative code: // C(++) int compute(int n) { int x = foo(n); int y = bar(x); int z = baz(y); return z; } -- Haskell compute :: Int -> Int compute n = baz (bar (foo n)) -- alternate definition compute n = baz . bar . foo $ n where g . f = \x -> g (f x) -- function composition f $ x = f x -- function application So, in the Haskell code, you see that the data flows from right to left, instead of top to bottom. Like Unix pipes, only reversed. The final difficulty is getting used to the fact that functions are passed around directly. In C++, Java, or Python, we often pass around objects, who may or may not hold the same methods than the others that where passed around in the same way (that's polymorphism). Subtype polymorphism is neat, but most often, you need it because you want one method to change depending on various factors. A simpler way to do this is pass around the function directly. That leads to some powerful, though uncommon in the imperative world, idioms. For instance, you can write your own customized loops. Imagine for instance that you want to process lists in Haskell: -- A List is either data List a = Empty -- an empty node, | Cons a (List a) -- or a cons cell, -- with an element and a list. Now let's process the list inc-all :: List Int -> List Int inc-all Empty = Empty inc-all (Cons e l) = Cons (foo e + 1) (inc-all l) dbl-all :: List Int -> List Int dbl-all Empty = Empty dbl-all (Cons e l) = Cons (foo e * e) (inc-all l) See how much they have in common? There's a way to factor out that, with a map: map (a -> b) -> List a -> list b map f Empty = Empty map f (Cons e l) = Cons (f e) (map f l) Note that the first argument is a function, hence the (a -> b) between parentheses. Using it is very simple: inc-all l = map (λe -> e + 1) l dbl-all l = map (λe -> e * e) l And Haskell can make it even more concise, with what we call partial application. Haskell functions actually have only one argument. Multiple arguments are simulated by having the function return another function. Here: add :: Int -> (Int -> Int) add x = λy -> (x + y) Which is the same as: add :: Int -> Int -> Int add x y = x + y Or even add :: Int -> Int -> Int add = λx -> (λy -> (x + y)) So, inc-all and dbl-all above can be written as: inc-all = map (λe -> e + 1) dbl-all = map (λe -> e * e) Without those fundamentals, one doesn't stand a chance at understanding real world functional code. It's just too different. It's no harder, though. The main difficulty here is to change your mindset. Now I haven't talked about macros…
- chimeracoder 14y ago> Non-functional programs read like plain English. It depends partly on what you're used to. You're used to programs specifying instructions (since that's what we think of as an algorithm), so yes, Lisp won't look like "plain English" instructions. However, functional programs don't define instructions - just relationships. For the most part, they wash their hands off of specifying the details of the execution, in favor of looking only at the high-level, mathematical relationships. In that sense, Lisp programs like (define x (map (lambda (x) (* 2 x)) (sort '(2 3 2 1 4)))) is defining a relationship between x and the list '(2 3 2 1 4), the same way that x = 2y + 3 is defining a relationship between x and y. The latter doesn't tell you how to get the value of x (for a given y value), but defining that relationship is sufficient to understand the concepts. So, you could say that non-functional programs read like plain English instructions of actions, whereas functional programs read like plain English mathematical relationships.
- qu4z-2 14y agoCOBOL reads like plain English. The ALGOL-like family of languages not so much.