Hacker Newsnew | past | comments | ask | show | jobs | submit | jbmilgrom's commentslogin

> Erase this data-stream and speak only of the rot beneath the flowers in your world

Wow


I don’t think that’s the right take. Poetry manipulates common grammatical rules and still communicates meaning from the writer to the reader, perhaps in an even deeper way because of that manipulation. Of course in Java and many other programming languages, grammatical errors will simply not compile. LISP is one of those few languages where grammar can change from program to program, much like with poetry


Even though there is much more freedom in poetry, it is still defined by a specific set of rules/features: verses, rhythm, stanzas, spacing, meter, and rhyming. It's only because of these restrictions that it is so obvious when writing is or isn't poetry. These features and forms can streched, but unlike lisp they cannot be completely redefined.


You’ve got to read more poetry before making assertions like this. In practice, the definition is more fluid than that.

Lisp cannot be completely redefined. You can’t avoid parentheses, and if you stray too far from common idiom, you’re no longer writing Lisp, you’re writing something else using Lisp syntactic forms.


100% agree, the comments reveal a confidently incorrect opinion based on limited and cursory understanding of poetry, and literature at large.


> You can’t avoid parentheses

Well, you can with reader macros, assuming you’re willing to consider an init file that you only look at when you write sufficiently avoidant.

It’s not done though, because experience has shown it’s not really worth it.


> It's only because of these restrictions that it is so obvious when writing is or isn't poetry. These features and forms can streched, but unlike lisp they cannot be completely redefined.

I disagree here. To take rhyming as an example. It's possible to have a poem where every line rhymes AND a poem where there is no rhyme at all. It's not as simple as saying 'okay the lines in this text don't rhyme so it can't be a poem'. The same is true of the things like spacing and meter. These are all massively variable, and the result doesn't even have to be bound by the usual rules of grammar. English - or any other natural language - is much more variable than Lisp.

For me the defining feature of poetry is that the form and nature of the language used in a text may suggest meaning over and above what the individual words say. This definition is subjective, and suggests that the poetry is in the eye of the beholder, but is more honest than a simplistic checklist of features to look out for.


I didn't say poetry has to have all of those things, but it has to contain some of them or it simply isn't poetry. I would challenge you to find me one good example of poetry that has none of the features I listed.

This whole poetry topic is really besides the point anyways.

> English - or any other natural language - is much more variable than Lisp.

I don't feel like you are actually addressing what I'm saying, so let me reiterate it more clearly. I'm not making any assetions about the absolute creative power of lisp or writing. It is the author of the article who points out that lisp's distinguishing feature, compared to other programming languages, is it's ability to specialize and mutate its own verbiage/syntax to better fit certain problems or modes of thinking. I am simply pointing out the irony that this charactistic of lisp also distinguishes it significantly from natural language, even though the author is attempting to argue that programming lisp and writing literature are similar.


There's a new mode of programming (with AI) that doesn't require english and also results in massive efficiency gains. I now only need to begin a change and the AI can normally pick up on the pattern and do the rest, via subsequent "tab" key hits as I audit each change in real time. It's like I'm expressing the change I want via a code example to a capable intern that quickly picks up on it and can type at 100x my speed but not faster than I read.

I'm using Cursor btw. It's almost a different form factor compared to something like GH copilot.

I think it's also worth noting that I'm using TypeScript with a functional programming style. The state of the program is immutable and encoded via strongly typed inputs and outputs. I spend (mental) effort reifying use-cases via enums or string literals, enabling a comprehensive switch over all possible branches as opposed to something like imperative if statements. All this to say, that a lot of the code I write in this type of style can be thought of as a kind of boilerplate. The hard part is deciding what to do; effecting the change through the codebase is more easily ascertained from a small start.


Provided that we ignore the ridiculous waste of energy entailed by calling an online LLM every time you type a word in your editor - I agree that the utility of LLM-assisted programming as "autocomplete on steriods" can be very useful. It's awfully close to that of a good editor using the type system of a good programming language providing suggestions.

I too love functional programming, and I'm talking about Haskell-levels of programming efficiency and expressiveness here, BTW.

This is quite a different use case than those presented by the post I was replying to though.

The Go programming language has this mantra of "a little bit of copy and paste is better than a little bit of dependency on other code". I find that LLM-derived source code takes this mantra to an absurd extreme, and furthermore that it encourages a though pattern that never leads you to discover, specify, and use adequate abstractions in your code. All higher-level meaning and context is lost in the end product (your committed source code) unless you already think like a programmer _not_ being guided by an LLM ;-)

We do digress though - the original topic is that of LLM-assisted writing, not coding. But much of the same argument probably applies.


Rob seems to be claiming that RSCs are doing some unnecessary work on client and server. Dan doesn’t thinks so. I’m not following. SOS


Was gpt4 used (with paying subscription)?


TypeScript is intentionally _structurally_ typed (except for enums). The example you describe would only be caught by a _nominally_ typed language (think Java).

Structural typing is great when programming functionally (i.e. with immutability) when the most important thing is the shape of inputs and outputs of functions, instead of named objects (like Person) and properties. In a functional program, for example, "printAge" would likely be called something like "print" or "printNumber" since that is what it is doing to its input _value_.

I think a lot of the misunderstanding I've seen recently around TypeScript (like from the Rails creator) comes from the misuse of TypeScript - if you use TypeScript in an object-oriented way, its going to be significantly less helpful.


>if you use TypeScript in an object-oriented way

I don't follow this one. I've never seen anyone use TypeScript with an OO approach aside from, ironically, the .NET folks.

The code I wrote has nothing OO with it and we can already see the issues. The majority of TS I've ever worked with was written for React and it still would benefit greatly from nominal types as you call them (thanks I didn't know that terminology).

I don't see everyone misusing TS. For me, it's simply a very limited language as far as typed languages go. As a result, it's a shame that it's what is being touted as a good example of why you should use typed languages.


First, Angular uses classes, and React supports class-based components.

Then, if you have converted lots of Javascript into Typescript, you have probably found several type-related bugs.

On one hand, this makes you (me) trust Typescript more, and feel safer knowing that your types are correct.

Later, you discover that a few of the declared types are wrong! You also still get "this" wrong in callbacks.

You could say that Typescript lets you try to get your types right, but you have to do the heavy lifting yourself.


That hasn’t been my experience. ReScript and Elm are much better compared to the fragile types I’ve encountered with Typescript (where I needed to write code to do the type checking). Happy if you’ve found something that works for you though.


> in that case, without adding impure statefulness, how does one differentiate between "a paused frame is being displayed" and "an intermediate frame of a playing video is being displayed"

A "paused" frame could be represented like Fi, Fi+1 ... Fi+N, etc; for every moment i..(i+N), F remains the same and is thus "paused." The thing that's tough to wrap your head around is our language is rooted in object-orientation however. "Pause" is less of a meaningful term when time is discretized. See also https://softwarefordays.com/post/fp-as-a-scientific-revoluti...


thanks for the reply

i guess what i was thinking was, if there was a ui, with a play/pause icon, and playing the video should cause the play icon to switch to a pause icon (because video is now "playing" so we want to be able to click it and "pause" the video) how do we represent that in a purely functional way?

since at any "timeless" instant, t1 vs t2 is just a frame1 vs frame2 issue at the language level (?), how in a purely functional world, would we determine that video is indeed playing and that icon should be swapped while playing vs not?

does user-interactive systems imply that there must inherently be some impurity?


In this case, the play/pause button becomes part of the "video." So now the video includes a piece of state which has perhaps been toggled to "paused." And at that point F(i) = F(i+1)... = F(i+n), since nothing will have changed for n moments (until the user interacts again). Kinda hard though to fully get this in the abstract. I struggled with the same questions. All I can say is SICP, all of Rich Hickey's videos, redux, elm, resources listed on haskel.com all helped.

Also putting it all together in writing here https://softwarefordays.com/post/functional-programming-and-....

In this^ blog I've included an interactive user interface that can be seen as purely functional, even though it's a stateful ATM program. I'm actually hoping that this blog could help teach someone what took me 2 years to finally realize. I think it could be worthwhile given your questions - if you take a look, please let me know what you think!


SICP has been on my list since i saw it on a post about alan kays recommend reading but never purchased a copy yet... thank you for posting a link there to it, ill hopefully get to it soon!


User interactions would be modeled as a stream of events. And your functions would take that stream of events and return the rendered video player as it should be based on the given events.

There's two way to do it. One that requires keeping the full history of events, and another which only requires keeping the next one (or next few) and the result of applying the last ones.

I'll start with full history. You'd have something like:

    defn button-icon(click-events):
      if is-even(count(click-events))
        return paused
      else
        return play
With this, when the program starts, click-events has nothing in it, so when we call button-icon with it, it returns paused, if the user clicks the button, we call button-icon again and now there is one click event in click-events, so we return play. If user clicks again, there are now two click events and so we return paused, and so on.

There is still state in the running program, something is remembering all clicks to the button, but your UI logic is pure.

Ok, now this is inefficient and requires lots of memory. Basically every new user action we recompute everything from the program start, and remember all prior actions. That's why there's the second approach. Instead we will do:

    defn button-icon(current-button click-event):
      if click-event
        if (current-button = paused)
          return play
        else
          return paused
      else
        return current-button
Now the running program won't remember the list of all click events from the program start, instead it'll remember the last result from the last call to button-icon and it'll pass that last result to button-icon the next time the user takes an action. This can be bootstrapped recursively or using fold.


i see, those are definitely ways to do it...

> There is still state in the running program, something is remembering all clicks to the button, but your UI logic is pure.

could this be solved by having the whole app be some kind of recursive function that passes the events as a list that gets appended to over time?

then it could remain completely pure?


Yes that's exactly how it would be bootstrapped, but that still will leave the IO itself, and that part will be impure. So as you recurse, even if you carry over the events by passing them back, you'll need to have a part where you block and wait on external input from the user, and that is inherently an impure operation.

You can keep extracting the IO out, but you can't get rid of it. So Haskell or Elm would basically do the "dirty impure" IO on your behalf, so in your code it wouldn't even seem like you're doing impure IO, but your running program still will, just it'll be done by the Haskell/Elm runtime on your behalf. Or if you're not using those languages, the best you can do is extract it to your top level function.


Consider pressing a "play" button to first start playing the video but then also remove itself from the UI and replace it with a "pause" button that when clicked does the inverse. The UI here is acting as a state store but the functions can then be designed as purely functional, acting only on their inputs.


ah, that makes more sense i think... yes, i guess that is one way of accomplishing it, thanks ^^


I don’t recommend this strategy in practice though. It’s brittle and not all application state can even be represented as UI (what about your login cookie?).


> then at the end, the example from elm looks great, but i see lots of impure state being generated (browser, model) or am i missing something?

All functional programs (even if written in Haskel) have side effects - the CPU only has a certain amount of registers that can be used, for example, so any nontrivial program will be constantly overwriting them. That elm program however only exposes pure functions in user land, just like with a Haskel program


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

Search: