import Data.List (nubBy)
refuteGoldbach :: Integer
refuteGoldbach = head $ [ n
| n <- [4,6..]
, not $ n `elem` [ p1 + p2 | p1 <- primesTo n, p2 <- primesTo n ]
]
where primesTo n = takeWhile (< n) $ nubBy isMultiple [2..]
isMultiple m n = n `rem` m == 0
If you think you already know the answer to this computation, get yourself a Field's medal.And then there are pure functions. Every time you compute a function using an input no-one has tried before, you are probably computing something that is not already known. You do this routinely even with a calculator.
For example, a REPL keeps state in the messages it prints to the terminal and this state isn't visible in the pure function definitions and expression the program is concerned with.
Unfortunately I'm over 40, otherwise I would try
No one was saying "don't use state" they were saying we need to adjust how we use it.
Which part of the state, and when?
Is this your program?
// change anything, anywhere, in the entire database, the biggest state
execute_sql(user_input)
You might want controls around that state so not anyone can change it. It might be read only for some users - that is, immutable.Is this your program?
log_to_database(financial_event for $5.00)
You probably want your financial logs to be immutable. Nobody should be able to mutate that $5.00 event to be $500.00.Is this your program?
o.foo = complex_function(...)
... 1000 lines later ...
o.foo = null
... 1000 lines later in another file ...
o.foo.do_stuff() // oops! foo was set to null somehow - but where?
The above scenario has shared state with "foo". Somewhere it was set to null somewhere. It could be set to null anywhere in your program. Good luck tracking the bug. If "foo" was immutable, you would know immediately where null came from, because it can only be initialized one time. It lowers the cognitive load, knowing that certain actions are impossible makes it easier to focus on what matters.Is this your program?
thing = computation()
return thing + 2
Many program are a series of computations - fresh state is created on each line, nothing is mutated. There is no reason not to be using immutability. In fact, if immutability were throughout, a compiler wouldn't have to worry about things like aliasing.This is all the tip of the iceberg, there are many reasons to enjoy using immutability.
I guess what you are saying is that foo should not have been changed, but a new variable created called "can_do_stuff" and it should have been checked before the call do_stuff()
I think the old Carmack article linked somewhere below makes a very good case for why pure functions are a good thing, and I see the value of making small atomic changes to an apps state, but ultimately, almost every applications job is to mutate data.
Other sorts of streaming operations --- message in, transform to new object which is logged or put into a data store most certainly do not need mutation so long as they are cache friendly, performant. FP and friends might even argue: yah ok it's some 10 pct slower but no race conditions, no weird sync. Formal methods are easier there to deploy. Those secondary arguments can be effective too; I'd bite
You sir - should write flyers and product-copy :)