Monday, December 4, 2017

What can AI predict?

So there are lots of things that machine learning can predict and we can point to examples of them running in the real world. Things like:

  • image recognition of cat vs. dog
  • stock market prediction
  • is this a stop sign
  • is it a tumor?
In short, these are all basically identifying trends, but what kinds of things can it not predict?

For instance, can we train AI to identify the best amendments to add to soil to improve crop yield? What about the best treatment for patients with a disease. We can go up to a point, but how far can it go?

Friday, December 1, 2017

Clojure for Those Who don't want to Learn Clojure

I really like Clojure. As a general purpose language I have not found a language I like more.

But when a team I worked on told me that they were migrating our code to another language we had an influx of team members who had never read Clojure and had no real incentive to learn it.

I will be the first to admit that Clojure is different. I struggled to read it at first, and I'll bet that others who have never dealt with a LISP will struggle too. I hope that my insignificant drop in the massive sea of helpful Clojure literature might help you.

This guide is not intended to be a complete guide to Clojure, but it might help you read a few things you maybe hadn't seen before.

Before I go repeating what is already out there, take a look at these resources:
Honestly, if you read these resources, you probably never need to look at this post ... Imma gonna write it anyway.

Why is Clojure Different?

Before I begin, I feel like I need to explain my take on why Clojure is great. I'm not writing this to convince you that you should use Clojure, but so that you can understand the philosophy behind Clojure and help understand some of the decisions made regarding the language or code you may confront.

Simplicity

Clojure is a LISP. What that means is there is almost no syntax because virtually everything is a list. The fancy term for this is homoiconicity which means that Clojure code is data. A list starts and ends with parenthesis. () is an empty list.

Every function is a list and functions are invoked using lists. The first item in a list is usually a symbol to a function that is invoked. fn is a function that creates functions. defn is also function which creates functions. If you've ever looked at even the smallest part of Clojure code, you've probably seen these before.

Consider, conversely, how complex other syntax can be. In many languages there are special meanings for

  • ;
  • :
  • ,
  • //
  • \
  • (
  • )
  • {
  • }
  • |
  • ?
  • =
  • +
  • -
  • *
  • /
  • %
  • for
  • while
  • if
  • etc.

or some combination of the above and/or other symbols, and there are special rules on how to use them. With Clojure you invoke functions with lists, semicolons are for comments, and you have a relatively small number of special symbols. You may feel I'm being pedantic by adding in reserved keywords like for and while, but I included them, because in LISPs those are just functions and they are handled like any other function.

Clojure does have a little more syntax than more traditional LISPs because some additional syntax can be helpful for things like maps, vectors, and sets. Following are examples of the literal syntax followed by what happens when that syntax is read by the reader.

;map literal
{:key :value ...}     <== this
(map :key :value ...} <== transforms to this

;vector literal
[0 1 2 3]
(vector 0 1 2 3)

;set literal
#{1 2 :bugga}
(set [1 2 :bugga])

Again, I may be accused of being pedantic, but I will say this, there are a lot fewer symbols with special meanings in Clojure, and when you see them they always mean the same thing. I will admit, that when you start working with macros you have more special symbols, but for most of your work in Clojure you'll only confront the symbols I mentioned already.

Power

Understanding that everything is a list if vital to understanding just how simple LISPs can be. Because the syntax of Clojure is so simple, it is more (not less!) powerful than many other languages. It literally allows you to extend functionality of the language. If there is a language feature you can't find in Clojure's core, you can write it. This is done using macros. Macros are beyond the scope of this post, but what they do is take a list (the parameters you pass in) and reorganize the contents of the list to something the reader already understands. For example. I mentioned that defn was a function, which is true, but only because macros are functions. defn is a macro that rewrites the contents it is passed.

(defn hello-world [name]
  (str "Hello, " name))

Is really a shortcut for

(def hello-world
  (fn [name]
    (str "Hello, " name)))

If your language doesn't have a foreach, but you want one, you probably can't add it, but you can extend the language with Clojure.

REPL

The REPL is a sandbox environment that makes it easy to test your code without going over a lot of hurdles. A lot of other languages are starting to use a command line style REPL (though they all call it something different) so you may already be familiar with the concept. When working with code that you don't understand, run it in the REPL to see what it does.

Functions

By default you cannot mutate bindings, once a binding is created it will always be that value. There is one way to get around this (that I sometimes find useful, but might make other Clojure developers cringe) and that is with the let function.

;let bindings allow you to shadow variables
(let [x 1
      x 3]
  x) <== returns 3

But it is important to know that each binding for x is a different reference underneath. Immutability is very useful especially when dealing with concurrency.

I know that my first question when I was told that you couldn't mutate variables was, "... well... how do you do anything then?"

The answer is quite simple—functions.

Functions can contain an arbitrary number of parameters. (+ 1 2 3 4 5 ...) returns 1 + 2 + 3 + 4 + 5 + ....

Functions can be called, passed, or created anywhere in your code. One way to do a loop may be to use recursion:

;recursion
(defn sum-list
  ([l] (sum-list l 0))
  ([l s] (if (empty? l)
           s
           (sum-list (rest l) (+ (first l) (or s 0))))))

This creates a multi-arity function (multiple variable signatures are allowed) if you call (sum-list [1 2 3]) the code will call sum-list again with the list passed and 0 as the sum. It will then call sum-list with all of the items except the first item, and with the sum of the first item in the list and the sum passed forward (0). It will keep doing this until there is no more list and then it will return the final sum.

There are two things I'll say about this. First, I invoked sum-list inside the two arity section, but I really should have used recur, I did this for clarity. Second, I don't think I've written any code that used recursion that is currently being used in a production environment. I've used map, reduce, and other functions that iterate over a list of items, but I don't know if I've ever needed to use recursion. With that in mind, I'll show a couple ways to write this

(defn sum-list [l]
  (reduce (fn [sum item] <== creates a function that takes the current sum and the current item in the list
             (+ sum item))
          l))

(defn sum-list [l]
  (reduce + l)) <== since + is a variable arity function, this works too

(defn sum-list [l]
  (apply + l))

These are all equivalent ways to do a sum in addition to the + function already shown.

Tips and Tricks

Now that I've had a chance to explain a little about why Clojure is so powerful and why someone might want to use it, I want to take a moment to write a few things you may not see in other languages.

Default Values Wrapped in (or)

In many languages, when you want to have a default value for a variable you must wrap this in an if block.

#pseudocode for default
function sum(a, b){
  if(a == null){
    a = 0;
  }
  return a + b;
}

If you're familiar with JavaScript you'll notice that a common way to deal with this is to use an or.

#same functionality in javascript
function sum(a, b){
  a = a || 0;
  return a + b;
}

- or -

function sum(a, b){
  return (a || 0) + b;
}

This works because JavaScript uses truthy values. You can do the same thing with Clojure.

; same functionality in Clojure
(defn sum [a b]
  (+ (or a 0) b)

Threading macros.

There are two threading macros, thread-first and thread-last. These functions are an awesome way to skip most of the parenthesis and it makes your code easier to read. For example, if you had the map:
{:a {:b {:c {:d {:e "blarg" :something-else :stuff}}}}}

and you wanted the value found in [a b c d e] you have multiple options. You could use get-in like this:

(get-in x [:a :b :c :d :e])

or this

(:e (:d (:c (:b (:a x)))))

But you could also do this:

(-> x :a :b :c :d :e)


which would extend it to this:

(:e (:d (:c (:b (:a x)))))


The threading macro threads the return of one call into the first (or last) parameter of the next function in line. This is useful when you have several transformations you want to do on the same thing. For example. Let's say you wanted to multiply x by 10, divide the returned value by 17, then add 2 and get the modulus of 100:

(-> x
  (* 10)
  (/ 17)
  (+ 2)
  (mod 100))

may easier to read than

(mod (+ (/ (* x 10) 17) 2) 100)

Clojure Spec

Clojure Spec is honestly a revelation! It allows the flexibility of a dynamically typed language to leverage the power of a type system. It does this so well, in fact, that Clojure Spec is more powerful than the type systems of most languages I've seen. I've already listed it, but I would visit https://clojure.org/guides/spec to read more.

Anonymous Functions and Partial

Anonymous functions allow you to create a new function from an existing function.

#(str % %2 %3)

is shortcut for

(fn [a b c] (str a b c))

You simply take the parameters that are passed in, in numbered order % or %1, %2, %3, ... %n and you pass them to the function you're calling. You cannot nest more than one anonymous function, but even one is helpful.

Partial is also a shortcut for creating new functions.

(def add-3 (partial + 3))

creates a function add-3 that when called will add 3 to the value(s) passed to it.

Tuesday, July 11, 2017

Plans vs. Planning

"Plans are worthless, but planning is everything." ~ Dwight D. Eisenhower
I find this quote really interesting. I think it implies that we need to be doing due diligence in determining how we should accomplish something, but that we need to be willing to change course when inevitable problems arise. Planning is important, not because of the plan that is created, but because (done properly) it helps you find pitfalls and problems that could arise on your way to your goal.

I think this notion of agility is important. It means that we take time to anticipate what is coming and therefore anticipate counter measures. Unfortunately, I think that Agile (with a capital A) has gotten a bit out of hand. Agile development is about teams taking control, but it seems that so many of the Agile frameworks are about taking control from the developers.

One reason for this, I think, is that self organizing teams should be improving and developing what is needed, but there is a fear that team members won't know what is needed unless you tell them what to do.

There are probably other reasons too...

I dream of a world where developing software is about developing software, not about managing the process developers are expected to follow.

Tuesday, May 2, 2017

gitstats

A while ago I discovered gitstats which is a cool tool to do some quick analytics on your code base including the lines of code, number of commits by author, types and counts of files, etc.

More than a year later and I lost that tool with the move to a new computer, but I was asked today to see some of those statistics again. Alas, the brew install command I used last time yielded no results (I guess it got moved or something) so I spent some time trying this and that until I was again able to run a report.

These steps are obvious in retrospect, but I don't want to forget them so I'm going to write them down:

  • Create a symbolic link to python2
    • gitstats requires python2, but the latest version of macOS doesn't have it. To further add to some confusion macOS has a System Integrity Protection feature which requires us to make a symbolic link slightly differently.
    • sudo ln -s /usr/bin/python2.6 /usr/local/bin/python2
  • Next install GnuPlot which is a dependency used in gitstats
    • brew install gnuplot
  • Now clone the repo
  • An run it
    • cd gitstats
    • .gitstats ~/Projects/source-repo ~/Projects/source-repo/target/stats
      • i.e. .gitstats [path to repo] [path to output dir]
Hope this helps.

Thursday, April 27, 2017

One Last Move

I guess I'm just not hard core enough to use Jekyll (I also wanted to enable comments without managing third-party accounts, etc). If you want to find old posts go to archive.tuesdaydeveloper.com.