I don’t like infixes

All this stuff began with a tweet of mine in response to @unclebobmartin. While Mr. Martin said "I am becoming ever more convinced that clojure is the functional language to use", I argued that Clojure is the opposite of Literate Programming as (+ 1 2) is very far from my natural way of thinking 1 + 2.

My opinion is that the prefix notation of Clojure, and the resulting parenthesis pollution, makes this language very hard to read.

Then @fogus pointed out that there is nothing literate about the infix way of representing (< a b c d e f g). That's true, if we think of a C like implementation such as:

a<b && b<c && c<d && d<e && e<f && f<g

But, fortunately, we have Scala:

 
package net.fl.clojure
 
object ClojureDemo {
 
  case class RichList (list : List[Int]) {
    def isOrderedBy(f: (Int, Int) => Boolean) : Boolean = list match {
      case Nil => true
      case x :: Nil => true
      case x :: y :: xs => f(x, y) && listConverter(y :: xs).isOrderedBy(f)
    }
 
    def isAscendingOrdered = isOrderedBy(_ < _)
  }
 
  implicit def listConverter (list: List[Int]) = new RichList(list)  
 
  def main(args : Array[String]) : Unit = {
    println(List(1, 2, 4).isOrderedBy(_ < _))
    println(List(1, 20, 4).isOrderedBy(_ < _))
 
    println(List(1, 2, 4).isAscendingOrdered)
    println(List(1, 20, 4).isAscendingOrdered)
  }
}
 

So the lispish (< a b c d e f g) becomes List(a b c d e f g).isAscendingOrdered or, if you want to be more flexible List(a b c d e f g).isOrderedBy(_ < _)

9 commenti

  1. jneira:

    Mmm i think the only sin of prefix (or fortran postfix) notation is being less popular than infix one. There isnt a only “natural” way of lang syntax, neither real langs nor prog langs. I think learn to switch from one to another expand and improve your mind.
    F. e. x=x+1 is very common in imperative prog and its completely different in “natural” math and in a imperative lang.
    Your scala example have prefix and postfix notation, cause “List” is in first place and “isOrderedBy” is in last one and its very much verbose than in clojure and c.
    In haskell make a list have a real infix notation a:b:c:d:e:f:g:[]. isnt it strange? ;-)

  2. Franco Lombardo:

    I agree with you : learning to switch from infix and prefix notation could really
    expand and improve your mind. Anyway, at least in the european modern languages I know, the infix notation is preminent. So, if we want to go in the direction of literate programming, we should choose programming languages that can use it. Moreover, as you said, Scala, as natural languages, has a mixed notation, while Lisp-like ones are more rigid in the direction of infix notation.
    By the way, in Scala you could write println( (1 :: 2 :: 3 :: Nil).isOrderedBy(_ < _))

  3. jneira:

    Yum, i didnt know that the great influence of haskell on scala also applied to building lists.
    In scala,haskell (or c++ with operator overloading) you can choose or mix the notations you are more familiar (literally is familiar IMO) to build dsls close to english but it has a price: more sintactic sugar, more prone to errors and less elegance. But “elegance” is still more subjective than “naturalness” :-P

  4. fogus:

    You’ve slightly changed the original problem at hand and I’m a little confused about your insistence on the “infix notation of Clojure”, but I’ll bite.

    The original premise was built on finding the monotonically increasing order of a number of arguments, which in Scala could be written as a function isminc:

    def isminc(a:Int, b:Int, c:Int, d:Int, e:Int):Boolean = a < b && b < c && c < d && d < e
    isminc(1,2,3,4,5)
    res6: Boolean = true

    That’s Scala, not C. You know the Clojure solution, so there is no need to cover that ground, but let’s put it into a function:

    (defn minc? [a b c d e] (< a b c d e))
    (minc? 1 2 3 4 5)
    true

    This is the original premise, and I would contest that the Clojure example is far more readable. However, by changing the problem in the way you did, you’ve actually helped to prove my original point. That is, you’ve taken a problem solved by a somewhat verbose infix solution, put it into a list and made it into a more flexible method call *prefix* solution. Your way (or some variant thereof… I would have probably used a Trait instead, but I realize that you want to keep things as compact as possible) was probably the correct way to solve this particular problem. But what happens if you need to compare more than just Ints? What if you need to mix them? BTW: I like Scala and I use it every day, so don’t take this as a slam against it. Instead, people like to pick and choose straw-man arguments against prefix notation without thinking through the vast number of cases where it makes sense. Even if your code was littered with a vast number of 1 + 2 then it’s debatable that using (+ 1 2) instead makes things harder to read.

  5. Franco Lombardo:

    @fogus

    My point is that, with a flexible language like Scala, you can have many solutions: you can use the prefix notation, or the infix one if you feel it better. In other languages you have only one choice, which, I think, most of the times is far less readable.

  6. Franco Lombardo:

    @jneira
    You say “more sintactic sugar, more prone to errors and less elegance”.
    I agree about syntactic sugar, while about the point of “error proness” I think it’s in someway true, even if, on the other hand, you must consider how many errors you’ll do in a language that’s not “clear”.
    About elegance, well, you already said…

  7. nibble:

    my 2 cents:
    * Mixing infix and prefix notation, like you do in your scale example, don\’t seems to me \"more clear\" than a pure infix (C) or prefix (clojure) solution.
    * You talk about Literate Programming, but prefix and infix notation has nothing to do with LP. You are talking about code clarity, and seems to me that here you are saying that infix notation is \"more clear\" because it\’s more widespread…

    regards
    nibble

  8. Franco Lombardo:

    Here I use the term “Literate Programming” not in the strict Knut’s sense, but in the meaning, that is now widespread, of a style of programming that mimics natural languages. See, for example, this post on java.net. (But you can find a similar usage in many articles on Behaviour Driven Development).
    Anyway, even if my opinion is that the maximum of code expressivity is gained by mixing infix and prefix notations, as I told before, you can have a purely infix Scala code using (1 :: 2 :: 3 :: Nil) isOrderedBy (_ < _)

  9. Franco Lombardo:

    @fogus
    You said “what happens if you need to compare more than just Ints? What if you need to mix them?”
    Well, here is an example:

    package net.fl.clojure
    
    object ClojureDemoGeneric {
      case class RichList[A] (list : List[A]) {
        def isOrderedBy(f: (A, A) => Boolean) : Boolean = list match {
          case Nil => true
          case x :: Nil => true
          case x :: y :: xs => f(x, y) && new RichList[A](y :: xs).isOrderedBy(f)
        }
      }
    
      implicit def listConverter[A] (list: List[A]) = new RichList[A](list)  
    
      def main(args : Array[String]) : Unit = {
        //lexicographic ordering: prints true
        println(List("a", "c", "z").isOrderedBy(_ < _))
    
        //natural nubers ordering: prints false
        println(List(1, 20, 4) isOrderedBy (_ < _))
    
        //floating point ordering: prints true
        println((1.0 :: 2.5 :: 3.9 :: Nil).isOrderedBy(_ < _))
    
        //custom ordering: prints false
        println(List("one", 2, 3.0) isOrderedBy ((x, y) => x.toString() < y .toString()))
      }
    }
    

Lascia un commento

You must be logged in to post a comment.