Hacker News new | ask | show | jobs
by dustingetz 3408 days ago
> is there a well-defined ordering? > a = 0; b = 1; c = a + b;

In pure functional languages, these expressions form a dependency graph and the interpreter or compiler may choose an ordering and may cache intermediate results

We may even represent the program itself as a graph, just like you suggest with ML programs, but this is a general purpose program

Obviously we can't do this in imperative languages.

I think pure functional programming enables this future of thinking about programs as graphs and not as text.

1 comments

Back in the late 80s/early 90s after I learned C, I remember wondering in awe how in the world compiler optimizations worked. But they do the same thing, they build (often intricate) dependency graphs. In the end, if a human can translate between imperative and functional programming, then there's no reason a machine can't.

I think the move towards functional programming, and putting the onus on developers to do the mental elbow grease of converting what are largely macro-style tasks (do this, do that) into functional code (feed this transform into this one) has done a great disservice to software engineering, especially with respect to productivity.

For a specific example: I use map() frequently with a use() clause or some other means of passing immutable variables to the inner scope. I have done the work of building that dependency graph by hand. But I should be able to use a mundane foreach() or even a dreaded for() loop, have the compiler examine my scope and see that I'm using my variables in an immutable fashion, and generate functional code from my imperative code.

What I am getting at is that in the olden days we used synchronous macros do a series of tasks and even though it was mediocre at best, it gave tremendous leverage to the developer. Today the amount of overhead required to map-reduce things or chain promises and carry the mental baggage of every timeout and failure mode is simply untenable for the human brain beyond a certain complexity. What we really need is to be able to read and write code imperatively but have it executed functionally, with every side effect presented for us.

I realize there is a lot of contradiction in what I just said but as far as I can tell, complexity has only increased in my lifetime while productivity has largely slipped. Shifting more and more of the burden to developer proficiency is just exactly the wrong thing to do. I want more from a typical computer today that is 1000 times faster than the ones I grew up on.

> I think the move towards functional programming, and putting the onus on developers to do the mental elbow grease of converting what are largely macro-style tasks (do this, do that) into functional code (feed this transform into this one) has done a great disservice to software engineering, especially with respect to productivity.

I think you've got this exactly backwards. Functional programming lets you think at a higher level of abstraction (data flow) than imperative programming (control flow). The compiler then applies elbow grease to translate your high-level data flow transformations into low-level control flow constructs.

Let's translate your statement back a generation and see how it sounds: "I think the move towards structured programming, and putting the onus on developers to do the mental elbow grease of converting what are largely assembly-level tasks (branch, copy, add a value to a register) into structured code (if, while, for) has done a great disservice to software engineering, especially with respect to productivity."

Hopefully you can understand how silly that seems to a modern programmer.

I don't think that data flow is a higher level of abstraction to control flow. They're just different types of abstraction, and each has its strengths and weaknesses.

If you only ever work on things that map well to functional programming then you'll naturally think it's superior to imperative programming. Likewise, if you only ever work on things that map well to imperative programming, then the functional programming approach seems a bit silly.

Functional code can represent an imperative program (using temporal logic or state monads), so it can be used for domains where you would use imperative code.

It will not always be easier, but it certainly provides more control over the execution flow.

Implementing an algorithm in a functional language almost always requires less code than implementing the same algorithm in an imperative language. That is direct evidence that functional languages are more abstract.
I enjoy functional programming because it's easier to reason about the code. Often it's easier to write it, but it's true that sometimes it's harder. I find that when I need to read and understand that code later, though, functional programming is usually a win. The same factors that make it sometimes harder to write - state must be passed around explicitly, idiomatic control flow constructs are less general, mutability is explicit and discouraged - make it much easier to understand later, because the interactions between different parts of the system are very clear. Compilers can certainly transform imperative code into the same form in many cases, but the benefit of functional programming is for my ability to reason, not the compiler's.

That said, you can write spaghetti code in any language. =)

Ya I'm not knocking functional programming (I prefer it as well) but I find it frustrating that so much of it breaks from the conventions we are accustomed to in C-style languages. Others around me can’t easily grok what I’ve written. Functional logic is the solution to the problem being tackled, but currently it has to be generated by hand, often in a write-only style. We are effectively writing functional assembly.

Take Swift for example (neat handle by the way!), it's probably the most pedantic language I have ever used. Personally I don't believe that it can be written without compiler assistance, especially when dealing with real-world data like JSON where pretty much anything can be optional. It's a language that makes me feel like anything I try will be rejected outright. It gets us halfway to functional programming with "let" and passing variables as immutable to callbacks by default, but then breaks too far from the contextual assumptions that we've built up in languages like C and javascript to "just work" when we try things. I feel misgivings about Rust for precisely these same reasons.

At this point the only functional language I've found that's somewhat approachable from an imperative background is probably ClojureScript, which is basically just Scheme running in one-shot mode, switching to Javascript to get the next piece of data instead of forcing the developer to use monads. It’s not even close to how I would design a functional language, but it’s substantially more approachable than say, Haskell.

I’m to the point where I am thinking about rejecting all of this and programming in synchronous shell-scripting style in something like Go, to get most of the advantages of Erlang without the learning curve. If languages aren’t purely functional, then I don’t believe they offer strong enough guarantees for the pain of using them. And purely functional languages can’t offer the leverage that scripting can, because they currently can’t be transpiled from imperative ones. It’s trivial to convert from functional to imperative, but basically impossible to go the other direction. They do nothing for you regarding the difficult step (some may argue the only step) of translating human ideas to logic. I think that’s the real reason that they haven’t achieved mainstream adoption.

This is a more fundamental issue though, we(the software industry as a whole) need to throw off the shackles of languages like C.

Swift is probably one of the worst examples when it comes to functional programming because it's still a C like language with some FP like things in the stdlib. So you get none of the advantages and some inconsistencies weighing it down.

Yes, I agree that Swift is 'too C-like', and besides, I was looking at Kotlin first, and it seems almost exactly the same syntactically. I like the J programming language, which allows for very small programs due to the composing and abstracting of functions. J's use of high-level abstraction using ASCII characters to represent functions (operators - verbs, adverbs, nouns...) seems to scare a lot of people away from it. The irony is of course the move towards array-computing hardware, GPUs and FPGAs that lend themselves for a perfect match with array-based languages like APL/J/K/Kona and other, and yet we mold array/vector libraries or patches to the C-style languages to enable programming GPUs People get comfortable with their PLs like their native tongue. It's why I would hear Westerners think a Chinese child was being particularly whiny compared to their own children or other Western children, when in reality the Cantonese-speaking child was saying the same type of things. Being American and understanding some of what the child was saying in Cantonese allowed me to make that observation, and fully realize how our comforts and preconceptions operate on how we perceive others and the world. This is why I try to be multilingual in PLs and spoken languages.

DeepUI seems like yet another way to tackle implementing our goals in a different language, and thereby also gain understanding into how we 'normally' do it.

i also think you have it backwards, FP is the higher level abstraction, pure FP is essentially pure math
This. Well put.