Live data from Hacker News

Mindset shifts for functional programming (with Clojure)

blog.janetacarr.com

31–40 of 100 posts

Re: Mindset shifts for functional programming (with Clojure)

#31
post #15

> Recursion over Looping Part of what makes Clojure a great programming language is that you don't have to believe this if you don't want to. Nobody has yet convinced me that recursion has any sustained advantage over looping. Using a loop is generally bad practice if a more specialised operation is available (don't loop if something is a simple map or reduce for example). But if the situation justifies a recursion t…

> Nobody has yet convinced me that recursion has any sustained advantage over looping. Looping may require trampolining or defunctionalisation, whilst recursion can be written much more directly and simply. As a very simple example (in pseudocode): even(n: uint): boolean = n match { case 0: true case n: odd(n-1) } odd(n: uint): boolean = n match { case 0: false case n: even(n-1) } Whilst these are pretty silly implem…

It's heretic and beside the point, but:

    bool odd(uint n){return n&1;} bool even(uint n){ return !odd(n);}
I can't help but think in terms of classic CPU.

Re: Mindset shifts for functional programming (with Clojure)

#32
post #24
post #8

Earlier quoted context omitted.

I don't understand where you come from with your argument. Recursion is also producing results that are "wrong answers" although I prefer to call them partial results. Just like a loop that is producing partial results as long as it has not finished yet.

> Recursion is also producing results that are "wrong answers" Not true. If you share your copy of: answer = sum [1..10] One viewer might see: answer = 3 + sum [3..10] and another viewer might see: answer = 6 + sum [4..10]. They may be "partial results", but they are correct and equal to each other. This is different from one viewer seeing 3 and another viewer seeing 6. "But can't you just hide the partial result unt…

You tend to not put temporary results of loops in instance variables, but in local variables. Which aren't visible externally at all.

And yes, if you do have that exceptional case of a complex algorithm that needs to store partial results in ivars as they are required by different methods and inconvenient to pass around individually, those ivars tend to not be exposed.

In fact, you'd more likely create a separate context object that you pass around, so also not visible externally.

Re: Mindset shifts for functional programming (with Clojure)

#33
post #15

> Recursion over Looping Part of what makes Clojure a great programming language is that you don't have to believe this if you don't want to. Nobody has yet convinced me that recursion has any sustained advantage over looping. Using a loop is generally bad practice if a more specialised operation is available (don't loop if something is a simple map or reduce for example). But if the situation justifies a recursion t…

Totally! Clojure is kind of great for this, the loop form in Clojure is really recursion as `loop` just provides a point(fn) for `recur` to return as well as a let binding. You could also just call `recur` in any fn. And, it has side-effect forms like do, doseq, dotimes, etc.

I'm glad you enjoyed the read though :)

Re: Mindset shifts for functional programming (with Clojure)

#34
post #6

Earlier quoted context omitted.

> If the recursion would be too complex, usually iteration is going to be easier to represent the solution in manageable chunks without requiring the reader to take everything in in one go. Perhaps? But the reason I reach for recursion is so that I don't have to first produce the "wrong answer", and then modify it until it's the "right answer". The sum of 1..10 is always 55. It isn't first 0, then 1, then 3, then 6,…

The only difference there is whether the "wrong answer" is visible while it's being calculated. Sums and factorials are the worst possible way to teach recursion because they look like a loop with a weird twist that adds conceptual complexity but doesn't seem to be there for any other reason. Recursion should really be taught by application to complex nested data structures. It's a lot clearer when you apply it to st…

It isn't, though. I recently started learning Rust and've basically been having to teach myself loops again. For over 10 years, I've not constructed a single loop; I've been getting it done by constructing my program with different combinators and recursion instead. And I've not ever felt that what I'd done would have been better with a loop.

It's even very seldomly that I even need if-statements. It's clearly a difference and I really would like to think of myself that I'm not _that_ deep into the cool aid.

This has been done with Scala, F#, Haskell and Elm.

With Rust, not only do loops feel more natural, they're very clearly the right tool.

Re: Mindset shifts for functional programming (with Clojure)

#35

If your team and you can read it later or when it goes wrong, then it's fine. I don't want to need to think hard about what code does, it should be clear. Or jump through 100 files to find a simple algorithm that has been divided into 100 pieces. I think people refactor to their own understanding or mental model or refactor-to-understand. I think there are cases where imperative code is intuitive and others where fun…

Agreed, cyclomatic complexity is definitely something to be aware of when designing functional programming systems.

Although, I disagree about Clojure's readability, but that's probably because I've been doing it for so long.

Interesting Java project you've got there. Reminds me of Clojure's core.async library and software transaction memory ;) (though, I know it's not exactly the same thing).

If I was transforming large streaming input from Kafka or Kinesis, I would probably reach for Cortex (a map-reduce style lib for Clojure), or I might rig up some strange, stream-to-lazy-seq adapter and reach for transducers as they have much better performance when dealing with larger input.

Re: Mindset shifts for functional programming (with Clojure)

#36
post #2

> Transformations over Instructions Hell yeah! The problem with "functional" programming is that a lot of people simply don't get you want to push as much of your program to be generic tools that transform things (ie FUNCTIONS!) When I start on a new problem I typically look at what kind of tools (functions) would make the solution concise and readable. Then create the tools and then write the solution with the tools…

I agree with your sentiment about recursion. It took me a damn long time to get used to it. But that's why I call it a mindset shift ;). If the codebase was written in Haskell, then there'd be no looping. Clojure is a bit odd in this case as it has a form called "loop" but it's really just a let binding over a fn, providing a point for `recur` to, well, recur to.

Re: Mindset shifts for functional programming (with Clojure)

#37
post #20

The advantage of clojure is in data centricity. It is not about shifting mind to recursion from looping. Clojure has a 'for' which is it's list comprehension loop. The actual fun of clojure: https://bitslap.it/blog/posts/fun-of-clojure.html

Clojure data type's are fantastic, but the main thesis of my post isn't what's required for FP in Clojure, rather, what's required to become comfortable with pure functional programming concepts which is why I reference Haskell a lot in the post. The examples just happen to be in Clojure.

Sorry for the confusion.

Re: Mindset shifts for functional programming (with Clojure)

#38

I think the main thing is not really FP vs whatever else but the most fundamental thing is declarative vs imperative. That is probably the biggest jump in mindset when coming from e.g. C or C++ to something like Haskell - that instead of telling the computer/compiler what to do, you describe what you want.

I think this would be correct for declarative programming languages, but I don't agree that Haskell is a declarative programming language. Haskell is pure functional programming in my mind. A declarative programming language might be something more akin to DML SQL for a RDBMS, or HCL for Terraform (pre-looping, v0.X).

Re: Mindset shifts for functional programming (with Clojure)

#39
post #15

> Recursion over Looping Part of what makes Clojure a great programming language is that you don't have to believe this if you don't want to. Nobody has yet convinced me that recursion has any sustained advantage over looping. Using a loop is generally bad practice if a more specialised operation is available (don't loop if something is a simple map or reduce for example). But if the situation justifies a recursion t…

> Nobody has yet convinced me that recursion has any sustained advantage over looping.

most sql systems support recursive queries. I believe recursive code can be analyzed by the system and executed in a the most efficient manner.

Loops have sideffects closely linking them to actual execution, which makes them blackboxes to the system.

Re: Mindset shifts for functional programming (with Clojure)

#40
post #18
post #15

> Recursion over Looping Part of what makes Clojure a great programming language is that you don't have to believe this if you don't want to. Nobody has yet convinced me that recursion has any sustained advantage over looping. Using a loop is generally bad practice if a more specialised operation is available (don't loop if something is a simple map or reduce for example). But if the situation justifies a recursion t…

I mostly agree, and proponents of FP shouldn't stress the recursion too much. When I program in Haskell, I rarely use recursion myself. Most loops are just maps and folds. Need to build another structure from existing structure? Foldl'. Once I understood that the value being folded can be arbitrarily complex, FP became simpler (but terser) than iterative programming for me.

Agreed, I rarely reach for recursion myself when developing. Most of my transformations are map, filter, and reduce. Although from time to time, I will combine them with recursion when necessary. I find recurring from a reducing function to be great for traversing or searching trees or other recursive data structures. Usually these are accompanied by a ton of comments for the next developer. :)
Post reply on HN