Live data from Hacker News

Destroy All Ifs – A Perspective from Functional Programming

degoes.net

101–110 of 226 posts

Re: Destroy All Ifs – A Perspective from Functional Programming

#101

Earlier quoted context omitted.

I was familiar with the problem but didn't have a name for it; thanks for providing me with one. What kind of work has there been on creating programming paradigms that make it easy to both add new types and new methods? Is it a CAP-theorem-type problem where every solution is a trade-off, or is there a way to have your cake and eat it too?

There are languages (libraries) that solve it. For reference, check Clojure's multimethods and OCaml's polymorphic variants.

The tradeoff is that techniques like multimethods significantly weaken the contract that people normally expect from methods/classes.

For example, if I'm writing a normal Java class, I know where I go to find methods dealing specifically with instances Foo (namely Foo and its children and direct users); with multimethods, it's more likely that there is some multimethod out there in an unrelated class that looks for instances of Foo.

Re: Destroy All Ifs – A Perspective from Functional Programming

#102

This is the starter code: publish :: Bool -> IO () publish isDryRun = if isDryRun then do _ This would be nicer if you could do multiple functions with pattern matching. In Elixir this would be: @spec publish(boolean) :: any def publish(true = _isDryRun) do _ = unsafePreparePackage dryRunOptions IO.puts "Dry run completed, no errors." end def publish(false = _isDryRun) do pkg = unsafePreparePackage defaultPublishOpti…

Or procedurally, you could just have two functions:

    publishLive
    publishDryRun
Which, of course, is not the point of the article either.

Re: Destroy All Ifs – A Perspective from Functional Programming

#103

Earlier quoted context omitted.

The annoying part there is the repeated "|x| x.". Rust should have syntax to reference a method of an object, instead of having to write a wrapper. So it'd look like .map_err(???.to_string()).

Groovy and Kotlin use the implicit "it" parameter for lambdas that take just one parameter, which is very convenient: listOf(1, 2, 3, 4).filter { it % 2 == 0 }

so does LiveScript

Re: Destroy All Ifs – A Perspective from Functional Programming

#104
post #5

Define true as a lambda taking two lazy values that returns the first, and false as one that returns the second, and you can turn all booleans into lambdas with no increase in code clarity. The straw man in the post - talking about a case-sensitive matcher that selectively called one of two different functions based on a boolean - is indeed trivially converted into calling a single function passed as an argument, but…

Someone else addressed the details of your counter argument, but I'd like to respond to it generally. It seems like every time someone writes an article on how to write better code, there are responses about how it doesn't make sense when taken to some logical extreme, or some special case, as if that invalidates the argument. (FP techniques in particular seem to provoke this.) But code design is like other design di…

It is a little tiring to hear all code design advice dismissed this way.

I notice this form of dismissal in virtually all internet arguments. It's like most people aren't aware of the difference between a strong argument and a sound argument.

Re: Destroy All Ifs – A Perspective from Functional Programming

#105
post #6

The idea that each type has its own control flow primitives is bothersome. It's taken over Rust: argv.nth(1) .ok_or("Please give at least one argument".to_owned()) .and_then(|arg| arg.parse:: ().map_err(|err| err.to_string())) .map(|n| 2 * n) I'm waiting for date.if_weekday(|arg| ...) Reading this kind of thing is hard. All those subexpressions are nameless, and usually comment-less. This isn't pure functional progra…

The annoying part there is the repeated "|x| x.". Rust should have syntax to reference a method of an object, instead of having to write a wrapper. So it'd look like .map_err(???.to_string()).

Rust does have such a syntax: map_err(ToString::to_string).

Re: Destroy All Ifs – A Perspective from Functional Programming

#106
post #46

Earlier quoted context omitted.

Thats why you use Lua, it lets you have multiple return values. So you can get a boolean back to let you know if the strings were the same, an int to know where they ceased matching and a boolean to let you know if they are case different. It's then up to the programmer to decide how much enlightenment they want. The destroy all IF reminds me of GOTO considered harmful of the 70's. There are other ways to fix the pro…

The Lua solution is clutter. Why return a boolean just to switch on it and then discard it?

Why create a lambda just to execute it and then discard it?

Re: Destroy All Ifs – A Perspective from Functional Programming

#107
post #14

I read everything I could find on the Anti-IF site and didn't understand what the mission is exactly. They qualify and mention they want to remove the bad and dangerous IFs, but I couldn't find examples that differentiate between bad ones and good ones -- are there good ones according to this campaign? I like using functional as much as anyone, and removing branching often does make the code clearer and remove the po…

I read everything I could find on the Anti-IF site and didn't understand what the mission is exactly. I have a similar problem, in that every time I try to understand the perspective of functional-programming advocates, I find that the authors always seem to illustrate their points with examples like this: match :: String -> Boolean -> Boolean -> String -> Bool match pattern ignoreCase globalMatch target = ... If I'm…

The problem's not on your end -- a lot of these blogs are just junk, probably the vast majority of ones that fall under "advocacy". As far as I can tell, the author's objection to conditionals is based on a misunderstanding of a different blog post[0]. It's nonsense.

Really understanding where FP is coming from requires an introduction to programming language semantics[1]. Interesting stuff, but not immediately useful to a working C programmer.

[0] https://existentialtype.wordpress.com/2011/03/15/boolean-bli...

[1] http://www.cs.cmu.edu/~rwh/pfpl.html

Re: Destroy All Ifs – A Perspective from Functional Programming

#108
General principle: for every possible refactoring, the opposite refactoring is sometimes a good idea.

So, yes, replacing booleans with a callback is sometimes a good idea. But in other situations, replacing a callback with a simple booleans might also be a good idea.

Also, advice like this is often language-specific. In languages whose functions support named parameters, boolean flags are easy to use and easy to read. If you only have positional parameters, it's more error-prone, so you might want to pass arguments using enums or inside a struct instead.

Re: Destroy All Ifs – A Perspective from Functional Programming

#109
post #5

Define true as a lambda taking two lazy values that returns the first, and false as one that returns the second, and you can turn all booleans into lambdas with no increase in code clarity. The straw man in the post - talking about a case-sensitive matcher that selectively called one of two different functions based on a boolean - is indeed trivially converted into calling a single function passed as an argument, but…

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 significan…

Inversion 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).

Re: Destroy All Ifs – A Perspective from Functional Programming

#110
post #6

The idea that each type has its own control flow primitives is bothersome. It's taken over Rust: argv.nth(1) .ok_or("Please give at least one argument".to_owned()) .and_then(|arg| arg.parse:: ().map_err(|err| err.to_string())) .map(|n| 2 * n) I'm waiting for date.if_weekday(|arg| ...) Reading this kind of thing is hard. All those subexpressions are nameless, and usually comment-less. This isn't pure functional progra…

The annoying part there is the repeated "|x| x.". Rust should have syntax to reference a method of an object, instead of having to write a wrapper. So it'd look like .map_err(???.to_string()).

It does. This could have been written

    .map_err(ToString::to_string)
as well. Works just fine with methods.
Post reply on HN