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

Citation needed.


STM isn't really used in Go like it is in Haskell.

Here's the example from a Go STM package that's based on Haskell STM. It has gotchas that you won't encounter in Haskell though, due to the nature of these languages.

https://github.com/anacrolix/stm/blob/master/cmd/santa-examp...

For the equivalent Haskell, check out the link at the top of the file.


It's very good. And quite short!


XSLT's matching rules allow a 'push' style of transform that's really neat. But you can actually do that with any programming language such as Javascript.


I used to use XSLT a lot, though it was a while ago.

You can use Javascript to get the same effect and, indeed, write your transforms in much the same style as XSLT. Javascript has xpath (still). You have a choice of template language but JSX is common and convenient. A function for applying XSLT-style matching rules for an XSLT push style of transform is only a few lines of code.

Do you have a particular example where you think Javascript might be more verbose than XSLT?


The term 'variable' is from mathematics. As others have said, the values of variables do vary but they do not mutate.


Yes, and math has the notion of "free variable" and "bound variable" [1].

[1] https://en.wikipedia.org/wiki/Free_variables_and_bound_varia...


They are often called bindings, not variables, so as to make it clear that they are just a name for a thing that will not change.


One way to get some intuition with FCIS is to write some Haskell.

Because Haskell programs pretty much have to be FCIS or they won't compile.

How it plays out is...

1. A Haskell program executes side effects (known as `IO` in Haskell). The type of the `main` program is `IO ()`, meaning it does some IO and doesn't return a value - a program is not a function

2. A Haskell program (code with type `IO`) can call functions. But since functions are pure in Haskell, they can't call code in `IO`.

3. This doesn't actually restrict what you can do but it does influence how you write your code. There are a variety of patterns that weren't well understood until the 1990s or later that enable it. For example, a pure Haskell function can calculate an effectful program to execute. Or it can map a pure function in a side-effecting context. Or it can pipe pure values to a side-effecting stream.


I used to write lots of haskell before deciding it didn't meet my needs. However, the experience provided lots of long-term benefits, including a FCIS design mindset.

Recently, I did a major python refactoring project, converting a prototype/hack/experiment into a production-quality system. The prototype heavily intermixed IO and app logic, and I needed to write unit tests for the production system. Even with fixtures and mocking, unit testing was painful and laborious, so our test coverage was lousy.

Partitioning the core classes into pure and impure components was the big win. Unit testing became trivial and we caught lots of bugs in the original business logic. More recently, we changed the IO from files to a DB and having encapsulated the IO was also a win.


May I ask you how you model your functional code in Python, in absence of Haskell's algebraic data types?


Full algebraic data types wouldn't have added much here. Product types are already everywhere, and we didn't need sum or exponential types.

Splitting IO and pure code was just routine refactoring, not a full redesign. Our app logic wasn't strictly pure because it generates pseudorandom numbers and logs events, but practically speaking, splitting the IO and shell from the relatively pure app logic made for much cleaner code.

In retrospect, I consider FCIS a good practice that I first learned with Haskell. It's valuable elsewhere, even when used in a less formal way than Haskell mandates.


I agree with the suggestion to study Haskell, I like Haskell quite a lot (although I don't write applications in it).


Surely transactions are a pretty good example of where functional core / imperative shell is a good guide. You really don't want to be doing arbitrary side effects inside your transaction because those can't be backed out. Check out STM in Haskell for a good example.


> You really don't want

And that's what this thread is filled with, and that's what I'm pushing back against.

> the RAI pattern is nice

> indicate if you are in different sections is nice

Style doesn't matter, flavour doesn't matter, wants don't matter, code "quality" (whatever that means) doesn't matter, niceness doesn't matter.

A transaction can be rolled back. If it can't, it's not a transaction.


I'd go a little further, though? Transactions have to be able to fail at the very last step. That could just be the "commit" stage. Everything up to that point could have been perfectly fine, but at commit it fails. More, the time of execution of that commit could be fairly far removed from the time of starting the transaction.

To that end, any style that tries to move those two time periods closer together in code is almost doomed to have some either hard to reason about code, or some tough edge cases that are hard to specify.

(Granted, I'll note that most transactions that people are dealing with on a regular basis probably do open and close rather close to each other.)


> I'd go a little further, though? Transactions have to be able to fail at the very last step. That could just be the "commit" stage.

I don't know what you mean by going a little further. I said transactions are 'all or nothing', not 'all or nothing or 99%'.


I meant only that there is no styling that can fix it. Some transactions will flat out fail partially done and have to be kicked to a reconciliation process to fix.

I grant that for things that are purely informational, this is not necessarily as accurate. But as the things reasoned about in a program get larger and larger, transactions span longer and longer timelines. With "all or nothing" not being nearly as clear cut as it is in smaller examples.

My go to examples are things like vending machines. (Granted, that almost certainly just shows my bias for state machines all the way down.)


I'm unclear what you're suggesting here. Are you suggesting you couldn't write a POS in Haskell, say?


My idea here is that, in many domains, you will have operations that are somewhat definitionally in the imperative camp. OpenTransaction being the easy example.

Can you implement it using functional code? Yes. Just make sure you wind up with partial states. And often times you are best off explicitly not using the RAI pattern for some of these. (I have rarely seen examples where they deal with this. Creating and reconciling transactions often have to be separate pieces of code. And the reconcile code cannot, necessarily, fallback to create a transaction if they get a "not found" fault.)


> Indeed, the general idea of imperative assembly comes to mind as the ultimate "core" for most software.

That's not what functional core, imperative shell means though. It's a given that CPUs aren't functional. The advice is for people programming in languages that have expressions - ruby, in the case of the original talk. The functional paradigm mostly assumes automatic memory management.


Right, I was just using that as "at the extreme" and how it largely exists to allow you to put a functional feel on top of the imperative below it.

I'm sympathetic to the idea, as you can see it in most instruction manuals that people are likely to consume. The vast majority of which (all of them?) are imperative in nature. There is something about the "for the humans" layer being imperative. Step by step, if you will.

I don't know that it fully works, though. I do think you are well served being consistent in how you layer something. Where all code at a given layer should probably stick to the same styles. But knowing which should be the outer and which the inner? I'm not clear that we have to pick, here. Feel free to have more than two layers. :D


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

Search: