Hacker News

Top stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. GPT-6 Sol and Luna(openai.com)
    147comments
  2. Claude Opus 5.5(anthropic.com)
    515comments
  3. OpenAI GPT–6 Astra breaks Enigma message that has resisted solution since 2005(cryptocellar.org)
    302comments
  4. WordPress: Unauthenticated path traversal leading to conditional RCE(github.com/wordpress)
    26comments
  5. Claude Opus 5.5 Intelligence, Performance and Price Analysis (Max)(artificialanalysis.ai)
    33comments
  6. There's a high chance of devices being sold with GrapheneOS preinstalled in 2027(grapheneos.social)
    43comments
  7. 16-bit Intel 8088 chip (c. 1985)(allpoetry.com)
    10comments
  8. OpenAI is well positioned to fast-follow Jev(arcturus-labs.com)
    128comments
  9. Launch HN: Coverage Cat (YC S22) – Umbrella insurance via your personal agent(coveragecat.com)
    14comments
  10. Writing Rust code that's fast by asking agents to make the code faster(minimaxir.com)
    26comments
  11. Apple has added persistent 'ads' to iOS, and it's driving users crazy(techradar.com)
    331comments
  12. Show HN: AI·rete·RAG – a Rete rule engine decides, RAG explains why(ai-rete-rag.com)
    discuss
  13. Solitaire Alone Together(solitairealonetogether.com)
    22comments
  14. Show HN: Drop – A rootless Linux sandbox with gVisor support(droprun.sh)
    40comments
  15. George Lucas Returns to Earth, Bearing Gifts(commonedge.org)
    1comments
  16. Can gzip be a language model?(nathan.rs)
    130comments
  17. One Minute Park(oneminutepark.tv)
    4comments
  18. AMD's random number generator can't generate a 0?(flatassembler.net)
    157comments
  19. Truman World(trumanworld.live)
    28comments
  20. Show HN: InstinctFlash – Run 5B world-action models in real time on Jetson Thor(github.com/general-instinct)
    discuss
  21. Training a model to identify AI-generated web content from structure alone(arxiv.org)
    2comments
  22. The Economics of Open-Weight Inference(ornn.com)
    16comments
  23. Relativistic raytracing(publish.obsidian.md)
    5comments
  24. MUNI Heritage Weekend in San Francisco(lawrence.lu)
    25comments
  25. I asked Meta’s Muse for its filesystem and it sent me 6.8GB(mouse.dev)
    116comments
  26. Meta’s Muse has a serious 0-day(arstechnica.com)
    37comments
  27. Vacate a drone restriction that criminalized recording immigration agents(eff.org)
    13comments
  28. Side-stepping the Secretary Problem, unwittingly(evalapply.org)
    1comments
  29. I said no and Apple said yes(dbushell.com)
    572comments
  30. MiMo v2.6(xiaomi.com)
    464comments

Can functional programming be liberated from the von Neumann paradigm?

52 pointsby 16y agoconal.net
24 comments
16y agoHN ↗

To carry the philosophy of functional programming to its logical extreme is to deny the existence of time. Some physicists have seriously suggested models that don't include time, but in the milieu of common human existence things happen and stuff has state.

State and time are always going to rear their ugly heads for functional programmers (often in the form of "the i/o problem"). There's just no way around it. This isn't to discount functional programming as a tool in the toolbox, but "philosophically pure" functional programming is an ideal as platonic and unreachable as the math it is derived from.

16y agoHN ↗

Beautifully said. I was going to post a comment saying the same thing, but you've put it in much better words than I would have. Thanks.

It's sad some programmer fall into the purity trap and try to make things as functional as possible and end up taking a lot more time than they normally would have, make the code incredibly hard to understand, etc.

I once fell into this trap and paid dearly. I'm a university student and for one of my semester projects I decided to try out pure functional programming. I ended up failing that class because I didn't finish the project, and doing bad in others because I spent ridiculous amounts of time doing the impossible project. (The project itself was easy - a simple 2D sidescroller game in C++, something I could have done in a week if I had been sensible; but writing a game in functional style in C++ proved to be incredibly hard.)

16y agoHN ↗

You shouldn't blame a particular programming style for the failure. Your real failure was an organizational one.

It seems that you have more experience with the imperative style than the functional style. And yes, it's always good to try a new style you aren't yet comfortable with, but you shouldn't do that in an important project. Also, you might have had better luck with Haskell or Lisp rather than C++. But here again, you shouldn't do that in a time contrained project if you aren't fit in that language yet.

Instead, you could have taken the week to implement it in the style you're comfortable with, and rewriting or refactoring it into another style to play around with it. That way, you would not only have eliminated the risk of failing. You would also have learned more, being able to compare both styles side-by-side.

16y agoHN ↗

You may have failed classes, but the lessons learned in working on something so improbable were probably worth the price of admission.

It's good to be too pure for learning purposes, because it makes you comfortable with a lot of nitpicky stuff. When you move towards commercial software, you won't get an environment that encourages you to take on the risky stuff. "Lean and mean" is the order of the day. So having the other experience gives you an edge in perspective.

16y agoHN ↗

I disagree. The lesson to be learned is not that pure functional programming it too extreme, but that it takes time to adopt that style.

As with any other style (OO, etc.), you won't get it right in your first attempt. It takes time to get a feeling for good design - in any style.

16y agoHN ↗

And C++ is not really the right language to try functional approaches. (You should at least at a garbage collector to vanilla C++ if you want to try.)

16y agoHN ↗

Well... you actually can try out functional approaches in C++, and even gain something out of it. It's just that doing so requires a sophisticated understanding of C++.

16y agoHN ↗

And probably a sophisticated understanding FP as well, if you want to apply it in such a hostile environment.

Not really a good idea when you are starting out, I guess.

16y agoHN ↗

Pure functional programming it is not about denying time. It's about separating the computing time from the programming model's time. Or equivalently, to separate the computing order from the order of real-world events.

That's why monads are an extremely powerful concept, and not just a hack to "avoid time". Using monads, you can compose evaluations in a certain order (model time), but that doesn't automatically mean they will be actually evaluated in that order (computing time). Well, if you use IO monads this will actually be the case. But you are free to define other monads which allow you to do strange things like looking into the future or checking multiple alternatives at once.

Pure functional programming forces you to always make an explicit distiction between these two kinds of time, and that feels buerocratic to those who are used to confound them. However, making that distinction usually yields to much better interfaces. So there is an extra effort, but also a big gain.

I strongly recommend to read Philip Wadler's The essence of functional programming before talking undifferentiated about the broad concept of time: http://homepages.inf.ed.ac.uk/wadler/papers/essence/essence....

16y agoHN ↗

I'm more or less a novice with FP, yet to learn a language more functional then Python, but this, and the article, are along the lines of something I was thinking of. Why exactly is it that I/O is stateful? A program, after all, is something that takes in input and spits out output, right? Why can't it be:

[Byte] -> [Byte]

main [data:rest] = ...

(sorry if I'm making up syntax or types, haven't properly learned Haskell yet). Well, my friends tell me, the problem is that often times you have to deal with timing, exceptions, etc. Well, fine:

[(Byte, Integer, Error)] -> [Byte]

main [(data, time, err):rest] = ...

As you said, no reason actual evaluation has to correspond to the logical order of evaluation.

16y agoHN ↗

I think this roughly corresponds to the original I/O system in Haskell, based on lazy streams. They were, by all accounts, an absolute bitch to program with. Continuation based I/O was slightly better, but monads were still greeted as liberators when they arrived on the scene.

16y agoHN ↗

In Haskell they like it better if a function returns the same value if it is called with the same arguments later on. Just like sin( pi ) gives the same answer every time you call it. If you start writing functions that take a file name and return the bytes then that function might return a different value the next time it is called assuming the file contents changed on disk. The same line of reasoning applies to db calls, user i/o, anything with random numbers etc.

16y agoHN ↗

But I'm not taking a file name, I'm taking a stream of data, for which the output should always be the same. This should be good enough for applications that deal with standard in and standard out, yes?

Though that's a good point, when it comes time to be opening files on the disk, it inevitably becomes stateful again.

16y agoHN ↗

In fact, you can have functions of type [Byte] -> [Byte], however, the problem is when you need to get the first set of bytes from a file or stdin. You could sort of read this as a function of type FileHandle -> [Byte], which will only very rarely even return the same value twice, let alone guaranteed-always.

16y agoHN ↗

Obviously you can't have truly pure functional code - I don't think anyone advocates that.

But non-functional code is much harder to debug (spooky action at a distance, etc) so a little bit more work upfront to isolate the non-functional code from the functional will make the debugging/maintenance phase (which are considerably longer than the 'initial writing' phase), easier.

16y agoHN ↗

That's exactly what the author is advocating.

16y agoHN ↗

How is this obvious?

It might make sense to say, "we can't build an effect-free computing machine", because we use transistors, and transistors get hot when they sink power, and things getting hot changes the entropy of the Universe... but it doesn't make sense to say, "we can't model an effect-free world, and program is if the world is effect-free".

(In fact, without effects, there is no world.)

16y agoHN ↗

Would you, then, agree with the statement: "There's no reason to write the sort of puritanically functional code that the article's author suggests we aspire to, because it would merely sit around and do nothing"?

Because apart from nothing, I'm not entirely sure what the author really thinks 100% pure functional code should do, when even input and output states are too impure to be allowed inside his Sanctified Garden of Jesus-Code, despite the fact that it's that mapping that we're explicitly interested in whenever we run a program. As far as I can tell, it's the "run a program" step that the author has a real problem with, and while he's welcome to subvert that paradigm, I don't see any hint of a way forward from it...if your program is meant to be fully composable at a level more granular than "program", shouldn't you be writing a library instead? Is that the suggestion?

From what I can tell, the author hasn't figured this out, either, he just thinks someone should.

16y agoHN ↗

It isn't often I hear people complaining that Haskell isn't pure enough.

16y agoHN ↗

Can anyone explain to me how the io monad gives referential transparency? So, say I have a function to read a file:

readFile :: String -> IO String

readFile filename = ...

At time t1, if I invoke it it returns say:

IO "Contents at t1"

At time t2, if I invoke it it returns say:

IO "Contents at t2"

Given that we supplied the function with the same argument (i.e. fname), and it returns two different values, how can they be said to be equal? I'm probably totally misunderstanding this but anyway....

16y agoHN ↗

It isn't just IO that breaks referential transparency, State does the same thing. The function get might have different values at different times.

Of course, get is a pure function mapping (State a) -> (State a) a, and the value hidden in the state is different between successive function calls.

Now just treat IO as State World, and think of the compiler as the function execState initialWorldValue.