Four MLs and a Python (2015)

(thebreakfastpost.com)

64 points | by breck 2440 days ago

6 comments

  • eatonphil 2440 days ago
    I'm really grateful for this guy's posts. It can be a nightmare figuring out how compilation works across different MLs. I just ported my Ponyo library for Standard ML to support MLton and his guides were a great aid. Keep up the good work!
    • cannam 2439 days ago
      Thank you!

      Did you notice this one? https://thebreakfastpost.com/2016/06/11/naming-conventions-i... It's definitely a bikeshed moment, but I had meant to drop you a line to ask you why you chose This_Sort_Of_Naming for structures in Ponyo. It seemed a bit of an outlier.

      I'm delighted to see you're still doing bits of work on Ponyo. I have a pleasant pipe-dream that, while frameworks and libraries for other languages rot because of language evolution, decades of random tiny personal SML library projects - written for a somehow still-modern language that never changes - eventually turn out to constitute a genuinely sound basis for new development work.

      • eatonphil 2438 days ago
        Ha! It's funny (and great!) to be featured there. The particulars of the naming convention are pure preference I suppose (and I recently simplified the naming of files [perhaps to the detriment of convention?]). I'm still trying to figure out proper naming conventions though and I'm not completely consistent. This makes the automated documentation generation I've tried to put in place hard...

        Anyway I'd like to point out that the namespacing exists at all because all structures in Standard ML are global by default. Some implementations have compilation managers that allow you to hide certain exports but Poly/ML does not. In general, if I define a String structure, I just overwrote the Basis String structure. (Ponyo exports a Basis structure up front that exports all overwritten Basis structures so you always have a way back). You could always overwrite these yourself, but _Ponyo_ itself prefixes all structures with their path for pseudo namespacing. But Ponyo also exposes them in a hierarchy for ease of use (the Ponyo structure embeds the Net structure which embeds the Http structure, etc.). But the original named structures are still accessible too. The worst part is signatures and functors. In the Standard ML standard, functors and signatures cannot exist inside of structures. This is a pain in the butt... And some non-standard extensions exist to support this (at least in SML/NJ maybe also in MLton). So in those cases you must ignore the structure access convention (Ponyo.Net.Http...) and use the full real name (Ponyo_Container_Dict). So in the worst case it's C-like (with only string/prefix "namespaces") and in the best case you can access and make shortcuts to intermediate structures (structure H = Ponyo.Net.Http).

        • cannam 2437 days ago
          Yes, it's disappointing that you can't just open a structure to wrap an entire other SML library or program. SML's module mechanism is usually very tidy but it has its awkward aspects, a pity for an otherwise so elegant language.
  • dfboyd 2439 days ago

      (ns fourmls.core
        (:gen-class))
    
      (defn csv-line-to-doubles
        [line]
        (map #(Double. %)
             (clojure.string/split line #",")))
    
      (defn barf-if-different-lengths
        [s1 s2]
        (if (not= (count s1)
                  (count s2))
          (throw (Exception. "Mismatched lengths"))
          s2))
    
      (defn sum-csv-lines
        [prev curr]
        (if (nil? prev)
          (csv-line-to-doubles curr)
          (->> curr
               csv-line-to-doubles
               (barf-if-different-lengths prev)
               (interleave prev)
               (partition 2)
               (map (partial apply +)))))
    
      (defn -main
        "I don't do a whole lot ... yet."
        [filename]
        (println
         (clojure.string/join
          ","
          (map str
               (reduce sum-csv-lines
                       nil
                       (->> filename
                            clojure.java.io/reader
                            line-seq))))))
    • joncampbelldev 2439 days ago
      Very nice.

      Perhaps using (partition 2 1 _) could be a clearer way to view the prev line instead of the reduce on a nil?

  • pmoriarty 2439 days ago
    This article doesn't talk at all about safety, which is one gigantic advantage modern statically typed languages have over traditional dynamically typed ones.

    It also doesn't talk at all about the pain of having to wrestle with the compiler in statically typed languages in order to get the damn thing to compile, nor with having to deal with inscrutable error messages that sometimes need years of type theory courses under your belt to understand.

    • aaronchall 2439 days ago
      Discussing "safety" isn't safe unless you properly define your terms. That is, otherwise, you don't know what type of "safe" people will interpret your words to mean.

      (Sorry, tongue got stuck in my cheek.)

      Of course, you probably mean type-safety? For example, if you try to add an integer and a string in Python you'll get a TypeError.

      Hindley Milner proves that we can infer the most general type of a program. I wonder if your concerns about safety are misplaced, but then I think of languages where one can add 1 and '1' and then I think you've certainly got a point.

      • f00_ 2439 days ago
        php for example(?)

        type casting there always seems horrible

    • fulafel 2438 days ago
      To me the interesting axis of safety in a program like this is IO errors (both input file and stdout), since those weren't covered by the specified failure cases and isn't covered by the likely casual testing that the developer will do. Python will throw an exception and stop the program since there is no IO exception handling, but what will the ML programs do?

      edit: I was wrong wrt output & Python: Python will report the exception but return a successful exit status (as tested by "python3 -c 'print(42)' > /dev/full")

  • a-nikolaev 2439 days ago
    A probably better OCaml implementation:

    https://gist.githubusercontent.com/a-nikolaev/b6fb099ebb28d7...

    With similar improvements to the solution posted in the article's comments, tail recursive, and no need for regular expressions. Works about 15% faster.

  • marmaduke 2439 days ago
    I did a similar comparison of expression evaluation in C, C++, Haskell, OCaml, Go and Python. Oh Java too:

    https://gist.github.com/maedoc/cfd893b8fed9ee57f1d3

    I enjoy these kind of comparisons more for the Rosetta Stone aspect than benchmarks, but I can't say they'd be useful for a real world project language choice.

  • Redoubts 2439 days ago
    > That’s Python 3. Python 2 was about a second faster.

    Of course it was.