8 ms·
A church encoded boolean is precisely isomorphic to every language's standard booleans (modulo strictness, perhaps) and doesn't offer any benefits; you're still
by buffyoda 10y ago
A church encoded boolean is precisely isomorphic to every language's standard booleans (modulo strictness, perhaps) and doesn't offer any benefits; you're still forking the program based on the information content of a single bit.
Let's take the following function invocation, which can be expressed with Boolean literals or Church encoded booleans, I don't care:
match true false
If you want to determine the significance of the boolean values passed to this function, it does not suffice to go to the definition of 'true' or the definition of 'false'.
Now take something like this:
match caseInsensitive contains
Even though I have used descriptive names here, it's almost beside the point; I could just have easily have used nonsense names:
match foobar quux
If you want to know what 'foobar' means, you can go to its definition, and see how it preprocesses a string and a pattern. You don't have to guess about the meaning of a bit.
As a result, the semantics of 'match' and its parameters are all communicated more clearly, with less room for error, and much more generality.
There need not be any syntactic overhead: it is merely the replacement of some flag with a lambda which cleanly encapsulates the effect that would otherwise be encoded in the flag. The way you invoke the function is the same, but instead of twiddling bits to get what you want, you pass functions whose meaning does not require (as much) subjective and possibly error-prone interpretation.
Note this also objectively simplifies the functions themselves, because they formerly contained conditional logic, but once you rip that out and give them no choice (invert the control!), they have less room to err, which makes them easier to get right, easier to maintain, and easier to test.
There is also another way to view the issue: with booleans, we first encode our intentions into a data structure (at the caller site), and then we decode the data structure into intentions (at the callee site).
Well, why are we packing and unpacking our intentions into data structures? Why not just pass them through?
Indeed, we do that by pulling out the code and propagating it to the caller site (possibly with names so you don't need significantly different syntax and can benefit from reuse). Then our code more directly reflects our intentions, because we're not serializing them into and out of bits.
I think the general principle applies to more than booleans, but it's easiest to see with booleans.
- greggman 10y agosince I'm not a fp expert what about a function like ctx.arc(10, 20, 30, 0, 6.28, false); There's nothing special about boolean. How do you encode all of those above into types in fp so that it's impossible to get them wrong and so they're self documenting? I hope you're not suggesting there be a horizontalFloat type and a verticalFloat type or are you?
- GregBuchholz 10y agoHow about keyword parameters... ctx.arc(center=Point(10,20), radius=30, beginAngle=0, endAngle=6.28, Clockwise); ...and don't forget about units of measurement/dimensional analysis. https://stackoverflow.com/questions/107243/are-units-of-measurement-unique-to-f https://stackoverflow.com/questions/107243/are-units-of-meas... ctx.arc(center=Point(10cm,20cm), radius=30mm, beginAngle=0rad, endAngle=6.28rad, Clockwise);
- buffyoda 10y agoThat helps quite a lot, although for several, it's more programming-by-name than programming-by-semantics. I'd like to be able to say the end angle has to be less than the start angle, that the unit has to be radians (AKA unit-less :), the unit of radius & that negative values are sensical, and so forth; and have all these properties checked by a compiler. Which I can do in some modern languages, surprisingly. :)
- lomnakkus 10y agoAssuming you're right about the guesses for those parameters, we could go a little further. Let's define data Directionality = Clockwise | Anticlockwise data AngularInterval = { beginAngle :: Double, endAngle :: Double, directionality :: Directionality } ... and then we're down to three parameters, all of different types (so no opportunity for mistakes, assuming static checking) and who knows, you might even have other uses for AngularInterval.
- buffyoda 10y agoI'm a big fan of the philosophy that "Every literal in a program is a bug." :) But I know what you're getting at! Personally, I'm a fan of programming with units and dimensions, and safely representing the distinction between absolute quantities and relative quantities. That doesn't mean I'd want an infinite number of "float" values for all possible units and dimensions, however; just a powerful enough type system I can give myself some help at compile-time for properly threading sensical values through my programs.
- mshenfield 10y agoInversion of control both increases the user's power (anything that implements a certain interface can be used) and adds an extra burden. Especially here, match caseInsensitive contains it takes a bit of thought to match the regex-like concept of "Case insensitive match flag" to "case insensitivity can be achieved by a transformation of the pattern and target so that case doesn't matter". Perhaps the right way to relieve this burden is to provide some simple functions that can be used for the common cases (caseInsensitive, caseSensitive) and a sensible default (caseSensitive).