Notes from Clojure/Conj 2017

It was a good Conj. Saw several friends and former co-workers of mine, heard some great talks about machine learning, and got some good ideas to take back to my current gig.

There were some dud talks, too, and others that promised one (awesome) thing and delivered another (boring) thing, but overall it’s inspiring to see how far Clojure has come in just ten years.

My notes from the conference:

DAY ONE

KEYNOTE FROM Rich Hickey: Effective Programs, or: 10 years of Clojure

  • clojure released 10 years ago
  • never thought more than 100 people would use it
  • clojure is opinionated
    • few idioms, strongly supported
    • born out of the pain of experience
  • had been programming for 18 years when wrote clojure, mostly in c++, java, and common lisp
  • almost every project used a database
  • was struck by two language designers that talked disparagingly of databases, said they’d never used them
  • situated programs
    • run for long time
    • data-driven
    • have memory that usually resides in db
    • have to handle the weirdness of reality (ex: “two-fer tuesday” for radio station scheduling)
    • interact with other systems and humans
    • leverage code written by others (libraries)
  • effective: producing the intended result
    • prefers above the word “correctness”, none of his programs ever cared about correctness
  • but: what is computing about?
    • making computers effective in the world
    • computers are effective in the same way people are:
      • generate predictions from experience
      • enable good decisions
    • experience => information => facts
  • programming is NOT about itself, or just algorithms
  • programs are dominated by information processing
  • but that’s not all: when we start talking to the database or other libraries, we need different protocols to talk to them
  • but there’s more! everything continues to mutate over time (db changes, requirements change, libraries change, etc)
  • we aspire to write general purpose languages, but will get very different results depending on your target (phone switches, device drivers, etc)
  • clojure written for information-driven situated programs
  • clojure design objectives
    • create programs out of simpler stuff
    • want a low cognitive load for the language
    • a lisp you can use instead of java/c# (his common lisp programs were never allowed to run in production)
  • says classes and algebraic types are terrible for the information programming problem, claims there are no first-class names, and nothing is composable
  • in contrast to java’s multitude of classes and haskell’s multitude of types, clojure says “just use maps”
  • says pattern matching doesn’t scale, flowing type information between programs is a major source of coupling and brittleness
  • positional semantics (arg-lists) don’t scale, eventually you get a function with 17 args, and no one wants to use it
  • sees passing maps as args as a way to attach names to things, thinks it’s superior to positional args or typed args
  • “types are an anti-pattern for program maintenance”
  • using maps means you can deal with them on a need-to-know basis
  • things he left out deliberately:
    • parochialism: data types
    • “rdf got it right”, allows merging data from different sources, without regard for how the schemas differ
    • “more elaborate your type system, more parochial the types”
    • in clojure, namespace-qualified keys allow data merging without worrying about colliding schemas (should use the reverse-domain scheme, same as java, but not all clojure libraries do)
    • another point: when data goes out over the wire, it’s simple: strings, vectors, maps. clojure aims to have you program the same inside as outside
  • smalltalk and common lisp: both languages that were designed by people for working programmers, and it shows
    • surprisingly, the jvm has a similar sensibility (though java itself doesn’t)
  • also wanted to nail concurrency
    • functional gets you 90% of the way there
  • pulled out the good parts of lisp
  • fixed the bad parts: not everything is a list, packages are bad, cons cell is mutable, lists were kind of functional, but not really
  • edn data model: values only, the heart of clojure, compatible with other languages, too
  • static types: basically disagrees with everything from the Joy of Types talk
  • spec: clojure is dynamic for good reasons, it’s not arbitrary, but if you want checking, it should be your choice, both to use it at all and where to use it

Learning Clojure and Clojurescript by Playing a Game

  • inspired by the gin rummy card game example in dr scheme for the scheme programming language
  • found the java.awt.Robot class, which can take screenshots and move the mouse, click things
  • decided to combine the two, build a robot that could play gin rummy
  • robot takes a screenshot, finds the cards, their edges, and which ones they are, then plays the game
  • lessons learned:
    • java interop was great
  • when clojurescript came out, decided to rebuild it, but in the browser
  • robot still functions independently, but now takes screenshot of the browser-based game
  • built a third version with datomic as a db to store state, allowing two clients to play against each other
  • absolutely loves the “time travel” aspects of datomic
  • also loves pedestal

Bayesian Data Analysis in Clojure

  • using clojure for about two years
  • developed toolkit for doing bayesian statistics in clojure
  • why clojure?
    • not as many existing tools ass julia or R
    • but: easier to develop new libraries than in julia (and most certainly R)
    • other stats languages like matlab and R don’t require much programming knowledge to get started, but harder to dev new tools in them
  • michaellindon/distributions
    • open-source clojure lib for generating and working with probability distributions in clojure
    • can also provide data and prior to get posterior distribution
    • and do posterior-predictive distributions
  • wrote a way to generate random functions over a set of points (for trying to match noisy non-linear data)
  • was easy in clojure, because of lazy evaluation (can treat the function as defined over an infinite vector, and only pull out the values we need, without blowing up)
  • …insert lots of math that i couldn’t follow…

Building Machine Learning Models with Clojure and Cortex

  • came from a python background for machine learning
  • thinks there’s a good intersection between functional programming and machine learning
  • will show how to build a baby classification model in clojure
  • expert systems: dominant theory for AI through 2010s
    • limitations: sometimes we don’t know the rules, and sometimes we don’t know how to teach a computer the rules (even if we can articulate them)
  • can think of the goal of machine learning as being to learn the function F that, when applied to a set of inputs, will produce the correct outputs (labels) for the data
  • power of neural nets: assume that they can make accurate approximations for a function of any dimensionality (using simpler pieces)
  • goal of neural nets is to learn the right coefficients or weights for each of the factors that affect the final label
  • deep learning: a “fat” neural net…basically a series of layers of perceptrons between the input and output
  • why clojure? we already have a lot of good tools in other languages for doing machine learning: tensorflow, caffe, theano, torch, deeplearning4j
  • functional composition: maps well to neural nets and perceptrons
  • also maps well to basically any ML pipeline: data loading, feature extraction, data shuffling, sampling, recursive feedback loop for building the model, etc
  • clojure really strong for data processing, which is a large part of each step of the ML pipeline
    • ex: lazy sequences really help when processing batches of data multiple times
    • can also do everything we need with just the built-in data structures
  • cortex: meant to be the theano of clojure
    • basically: import everything from it, let it do the heavy lifting
  • backend: compute lib executes on both cpu and gpu
  • implements as much of neural nets as possible in pure clojure
  • meant to be highly transparent and highly customizable
  • cortex represents neural nets as DAG, just like tensorflow
    • nodes, edges, buffers, streams
  • basically, a map of maps
    • can go in at any time and see exactly what all the parameters are, for everything
  • basic steps to building model:
    • load and process data (most time consuming step until you get to tuning the model)
    • define minimal description of the model
    • build full network from that description and train it on the model
  • for example: chose a credit card fraud dataset

Clojure: Scaling the Event Stream

  • director, programmer of his own company
  • recommends ccm-clj for cassandra-clojure interaction
  • expertise: high-availability streaming systems (for smallish clients)
  • systems he builds deal with “inconvenient” sized data for non-apple-sized clients
  • has own company: troy west, founded three years ago
  • one client: processes billions of emails, logs 10–100 events per email, multiple systems log in different formats, 5K–50K event/s
  • 10–100 TB of data
  • originally, everything logged on disk for analysis after the fact
  • requirements: convert events into meaning, support ad-hoc querying, generate reports, do real-time analysis and alerting, and do it all without falling over at scale or losing uptime
  • early observations:
    • each stream is a seq of immutable facts
    • want to index the stream
    • want to keep the original events
    • want idempotent writes
    • just transforming data
  • originally reached for java, since that’s the language he’s used to using
  • data
    • in-flight: kafka
    • compute over the data: storm (very powerful, might move in the direction of onyx later on)
    • at-rest: cassandra (drives more business to his company than anything else)
  • kafka: partitioning really powerful tool for converting one large problem into many smaller problems
  • storm: makes it easy to spin up more workers to process individual pieces of your computation
  • cassandra: their source of truth
  • query planner, query optimizer: services written in clojure, instead of throwing elasticsearch at the problem
  • recommends: Designing Data-Intensive Applications, by Martin Kleppmann
  • thinks these applications are clojure’s killer app
  • core.async gave them fine-grained control of parallelism
  • recommends using pipeline-async as add-on tool
  • composeable channels are really powerful, lets you set off several parallel ops at once, as they return have another process combine their results and produce another channel
  • but: go easy on the hot sauce, gets very tempting to put it everywhere
  • instaparse lib critical to handling verification of email addresses
  • REPL DEMO
  • some numbers: 0 times static types would have saved the day, 27 repos, 2 team members

DAY TWO

The Power of Lacinia and Hystrix in Production

  • few questions:
    • anyone tried to combine lysinia and hystrix?
    • anyone played with lacinia?
    • anyone used graphql?
    • anyone used hystrix?
  • hystrix : circuit-breaker implementation
  • lacinia: walmart-labs’ graphql
  • why both?
  • simple example: ecommerce site, aldo shoes, came to his company wanting to rennovate the whole website
  • likes starting his implementations by designing the model/schema
  • in this case, products have categories, and categories have parent/child categories, etc
  • uses graphvis to write up his model designs
  • initial diagram renders it all into a clojure map
  • they have a tool called umlaut that they used to write a schema in a single language, then generate via instaparse representations in graphql, or clojure schema, etc
  • lacinia resolver: takes a graphql query and returns json result
  • lacinia ships with a react application called GraphiQL, that allows you to through the browser explore your db (via live queries, etc)
  • gives a lot of power to the front-end when you do this, lets them change their queries on the fly, without having to redo anything on the backend
  • problem: the images are huge, 3200×3200 px
  • need something smaller to send to users
  • add a new param to the schema: image-obj, holds width and height of the image
  • leave the old image attribute in place, so don’t break old queries
  • can then write new queries on the front-end for the new attribute, fetch only the size of image that you want
  • one thing he’s learned from marathon running (and stolen from the navy seals): “embrace the suck.” translation: the situation is bad. deal with it.
  • his suck: ran into problem where front-end engineers were sending queries that timed out against the back-end
  • root cause: front-end queries hitting backend that used 3rd-party services that took too long and broke
  • wrote a tiny latency simulator: added random extra time to round-trip against db
  • even with 100ms max, latency diagram showed ~6% of the requests (top-to-bottom) took over 500ms to finish
  • now tweak it a bit more: have two dependencies, and one of them has a severe slowdown
  • now latency could go up to MINUTES
  • initial response: reach for bumping the timeouts
  • time for hystrix: introduce a circuit breaker into the system, to protect the system as a whole when an individual piece goes down
  • hystrix has an official cloure wrapper (!)
  • provides a macro: defcommand, wrap it around functions that will call out to dependencies
  • if it detects a long timeout, in the future, it will fail immediately, rather than waiting
  • as part of the macro, can also specify a fallback-fn, to be called when the circuit breaker is tripped
  • adding that in, the latency diagram is completely different. performance stays fast under much higher load
  • failback strategies:
    • fail fast
    • fail silently
    • send static content
    • use cached content
    • use stubbed content: infer the proper response, and send it back
    • chained fallbacks: a little more advanced, like connecting multiple circuit breakers in a row, in case one fails, the other can take over
  • hystrix dashboard: displays info on every defcommand you’ve got, tracks health, etc
  • seven takeaways
    • MUST embrace change in prod
    • MUST embrace failure: things are going to break, you might as well prepare for it
    • graphql is just part of the equation, if your resolvers get too complex, can introduce hystrix and push the complexity into other service
    • monitor at the function level (via hystrix dashboard)
    • adopt a consumer-driven mindset: the users have the money, don’t leave their money on the table by giving them a bad experience
    • force yourself to think about fallbacks
    • start thinking about the whole product: production issues LOOK to users like production features
  • question: do circuit-breakers introduce latency?
    • answer: a little bit at the upper end, once it’s been tripped

The Tensors Must Flow

  • works at magento, lives in philly
  • really wants to be sure our future robot masters are written in clojure, not python
  • guildsman: tensorflow library for clojure
  • tensorflow: ML lib from google, recently got a c api so other languages can call into it
  • spoiler alert: don’t get TOO excited. everything’s still a bit of a mess
  • but it DOES work, promise
  • note on architecture: the python client (from google) has access to a “cheater” api that isn’t part of the open c api. thus, there’s some things it can do that guildsman can’t because the api isn’t there
  • also: ye gods, there’s a lot of python in the python client. harder to port everything over to guildsman than he thought
  • very recently, tensorflow started shipping with a java layer built on top of a c++ lib (via jni), which itself sits on top of the tensorflow c api, some people have started building on top of that
  • but not guildsman: it sits diretly on the c api
  • in guildsman: put together a plan, then build it, and execute it
  • functions like guildsman/add produce plan maps, instead of executing things themselves
  • simple example: adding two numbers: just one line in guildsman
  • another simple example: have machine learn to solve | x – 2.0 | by finding the value of x that minimizes it
  • tensorflow gives you the tools to find minima/maxima: gradient descent, etc
  • gradient gap: guildsman can use either the clojure gradients, or the c++ ones, but not both at once
    • needs help to port the c++ ones over to clojure (please!)
  • “python occupies the 9th circle of dependency hell”: been using python lightly for years, and still has problems getting dependencies resolved (took a left turn at the virtual environment, started looking for my oculus rift)
  • demo: using mnist dataset, try to learn to recognize handwritten characters

The Dawn of Lisp: How to Write Eval and Apply in Clojure

  • educator, started using scheme in 1994, picked up clojure in 2009
  • origins of lisp: john mccarthy’s paper: recursive functions of symbolic expressions and their computation by machine, part i
  • implementation of the ideas of alonzo church, from his book “the calculi of lambda-conversion”
  • “you can always tell the lisp programmers, they have pockets full of punch cards with lots of closing parenthses on them”
  • steve russel (one of the creators of spaceware) was the first to actually implement the description from mccarthy’s paper
  • 1962: lisp 1.5 programmer’s manual, included section on how to define lisp in terms of itself (section 1.6: a universal lisp function)
  • alan kay described this definition (of lisp in terms of lisp) as the maxwell equations of software
  • how eval and apply work in clojure:
    • eval: send it a quoted list (data structure, which is also lisp), eval will produce the result from evaluating that list
      • ex: (eval ‘(+ 2 2)) => 4
    • apply: takes a function and a quoted list, applies that function to the list, then returns the result
      • ex: (apply + ‘(2 2)) => 4
  • rules for converting the lisp 1.5 spec to clojure
    • convert all m-expression to s-expressions
    • keep the definitions as close to original as possible
    • drop the use of dotted pairs
    • give all global identifiers a ‘$’ prefix (not really the way clojure says it should be used, but helps the conversion)
    • add whitespace for legibility
  • m-expressions vs s-expressions:
    • F[1;2;3] becomes (F 1 2 3)
    • [X < 0 -> -X; T -> X] becomes (COND ((< X 0) (- X)) (T X))
  • dotted pairs
    • basically (CONS (QUOTE A) (QUOTE B))
  • definitions: $T -> true, $F -> false, $NIL, $cons, $atom, $eq, $null, $car, $cdr, $caar, $cdar, $caddr, $cadar
    • note: anything that cannot be divided is an atom, no relation to clojure atoms
    • last few: various combos of car and cdr for convenience
  • elaborate definitions:
    • $cond: own version of cond to keep syntax close to the original
    • $pairlis: accepts three args: two lists, and a list of existing pairs, combines the first two lists pairwise, and combines with the existing paired list
    • $assoc: lets you pull key-value pair out of an association list (list of paired lists)
    • $evcon: takes list of paired conditions and expressions, plus a context, will return the result of the expression for the first condition that evaluates to true
    • $evlist: takes list of expressions, with a condition, and a context, and then evalutes the result of the condition + the expression in a single list
    • $apply
    • $eval
  • live code demo

INVITED TALK FROM GUY STEELE: It’s time for a New Old Language

  • “the most popular programming language in computer science”
  • no compiler, but lots of cross-translations
  • would say the name of the language, but doesn’t seem to have one
  • so: CSM (computer science metanotation)
  • has built-in datatypes, expressions, etc
  • it’s beautiful, but it’s getting messed up!
  • walk-throughs of examples, how to read it (drawn from recent ACM papers)
  • “isn’t it odd that language theorists wanting to talk about types, do it in an untyped language?”
  • wrote toy compiler to turn latex expressions of CSM from emacs buffer into prolog code, proved it can run (to do type checking)
  • inference rules: Gentzen Notation (notation for “natural deduction”)
  • BNF: can trace it all the way back to 4th century BCE, with Panini’s sanskrit grammar
  • regexes: took thirty years to settle on a notation (51–81), but basically hasn’t changed since 1981!
  • final form of BNF: not set down till 1996, though based on a paper from 1977
  • but even then, variants persist and continue to be used (especially in books)
  • variants haven’t been a problem, because they common pieces are easy enough to identify and read
  • modern BNF in current papers is very similar to classic BNF, but with 2 changes to make it more concise:
    • use single letters instead of meaningful phrases
    • use bar to indicate repetition instead of … or *
  • substitution notation: started with Church, has evolved and diversified over time
  • current favorite: e[v/x] to represent “replace x with v in e”
  • number in live use has continued to increase over time, instead of variants rising and falling (!)
  • bigger problem: some sub variants are also being used to mean function/map update, which is a completely different thing
  • theory: these changes are being driven by the page limits for computer science journals (all papers must fit within 10 years)
  • overline notation (dots and parentheses, used for grouping): can go back to 1484, when chuquet used underline to indicate grouping
    • 1702: leibnitz switched from overlines to parentheses for grouping, to help typesetters publishing his books
  • three notations duking it out for 300 years!
  • vectors: notation -> goes back to 1813, and jean-robert argand (for graphing complex numbers)
  • nested overline notation leads to confusion: how do we know how to expand the expressions that are nested?
  • one solution: use an escape from the defaults, when needed, like backtick and tilde notation in clojure
  • conclusions:
    • CMS is a completely valid language
    • should be a subject of study
    • has issues, but those can be fixed
    • would like to see a formal theory of the language, along with tooling for developing in it, checking it, etc
    • thinks there are opportunities for expressing parallelism in it

Day Three

Declarative Deep Learning in Clojure

  • starts with explanation of human cognition and memory
  • at-your-desk memory vs in-the-hammock memory
  • limitation of neural networks: once trained for a task, it can’t be retrained to another without losing the first
    • if you train a NN to recognize cats in photos, you can’t then ask it to analyze a time series
  • ART architecture: uses two layers, F1 and F2, the first to handle data that has been seen before, the second to “learn” on data that hasn’t been encountered before
  • LSTM-cell processing:
    • what should we forget?
    • what’s new that we care about?
    • what part of our updated state should we pass on?
  • dealing with the builder pattern in java: more declarative than sending a set of ordered args to a constructor
  • his lib allows keyword args to be passed in to the builder function, don’t have to worry about ordering or anything
  • by default, all functions produce a data structure that evaluates to a d4j object
  • live demos (but using pre-trained models, no live training, just evaluation)
  • what’s left?
    • graphs
    • front end
    • kafka support
    • reinforcement learning

Learning Clojure Through Logo

  • disclaimer: personal views, not views of employers
  • logo: language to control a turtle, with a pen that can be up (no lines) or down (draws lines as it moves)
  • …technical difficulties, please stand by…
  • live demo of clojure/script version in the browser
  • turns out the logo is a lisp (!): function call is always in first position, give it all args, etc
  • even scratch is basically lisp-like
  • irony: we’re using lisp to teach kids how to program, but then they go off to work in the world of curly braces and semicolons
  • clojure-turtle lib: open-source implementation of the logo commands in clojure
  • more live demos
  • recommends reading seymour papert’s book: “Mindstorms: Children, Computers, and Powerful Ideas”
  • think clojure (with the power of clojurescript) is the best learning language
  • have a tutorial that introduces the turtle, logo syntax, moving the turtle, etc
  • slowly introduces more and more clojure-like syntax, function definitions, etc
  • fairly powerful environment: can add own buttons for repeatable steps, can add animations, etc
  • everything’s in the browser, so no tools to download, nothing to mess with
  • “explaining too early can hurt”: want to start with as few primitives as possible, make the intro slow
  • can create your own lessons in markdown files, can just append the url to the markdown file and it’ll load (!)
  • prefer that you send in the lessons to them, so they can put them in the lessons index for everyone to benefit
  • have even translated the commands over to multiple languages, so you don’t have to learn english before learning programming (!)
  • lib: cban, which has translations of clojure core, can be used to offer translations of your lib code into something other than english
  • clojurescript repls: Klipse (replaces all clojure code in your page with an interactive repl)
  • comments/suggestions/contributions welcome

On the Google Anti-Diversity Memo

It’s horseshit.

From its title (“Google’s Ideological Echo Chamber”) to its claims that its author is the only human capable of rational thought without bias, to its assertion that modern feminist critique only exists because Communism failed, it’s filled with faulty logic and flawed arguments that wouldn’t have held water in any of the philosophy classes I took as a freshman.

It’s clearly a document meant to inflame, to incite, and most definitely not to encourage the kind of discussion the author claims over and over again to want to facilitate.

Let me be clear:

  • The gender pay gap is real. Its size varies across countries and industries, but it exists.
  • Studies of group decision-making show that those with a variation in viewpoints — particularly along gender lines — do better than those that lack such diversity.
  • Bias against women is long-standing in the technological fields, and should be combatted by any means necessary.
  • Feminism goes back a hell of a lot further than communism.
  • Claims of universal values for Left and Right ignore the historical context in which those labels arose, and how fluid the beliefs of the groups assigned those labels have been over time.
  • Affirmative-action programs are not “illegal discrimination”
  • Political correctness is the name commentators on the Right have given to an age-old phenomenon: politeness. Certain beliefs or expressions are always considered beyond the pale. Those expressions change over time. The recent trend in Western society has been to push insults of race or gender beyond the pale. This is not a new thing, it is not a new form of authoritarianism, it is not a symptom of a Fascist Left. It’s civilization. Rude people have always faced censure, and rightly so.
  • Finally, insisting that others are biased, while you are “biased” towards intellect and reason, is absurd. It’s a classic male power move. It denies your opponents any semblance of reason or thought. It’s dehumanizing. And it’s horseshit.

Introducing elm-present

I’m in love with Elm. No, really.

I don’t know if it’s just that I’ve been away from front-end development for a few years, but working in Elm has been a breath of fresh air.

When my boss offered to let us give Tech Talks on any subject at the last company meetup, I jumped at the chance to talk about Elm.

And, of course, if I was going to give a talk about Elm, I had to make my slides in Elm, didn’t I?

So I wrote elm-present.

It’s a (very) simple presentation app. Slides are json files that have a title, some text, a background image, and that’s it. Each slide points to the one before it, and the one after, for navigation.

elm-present handles reading in the files, parsing the json, and displaying everything (in the right order).

And the best part? You don’t need a server to run it. Just push everything up to Dropbox, open the present.html file in your browser, and voilà!

You can see the talk I gave the meetup here, as a demo.

Seven More Languages in Seven Weeks: Julia

Julia feels…rough.

There are parts I absolutely love, like the strong typing, the baked-in matrix operations, and the support for multi-type dispatch.

Then there’s the pieces that seem incomplete. Like the documentation, which is very extensive, but proved useless when trying to find out the proper way to build dictionaries in the latest version. Or the package system, which will install things right into a running repl (cool!) but does it without getting your permission for all its dependencies (boo).

All in all, I’d like to build something more extensive in Julia. Preferably something ML-related, that I might normally build in Python.

Day One

  • can install with brew
  • book written for 0.3, newest version is 0.5
  • has a repl built in 🙂
  • typeof for types
  • “” for strings, ” only for single-chars
  • // when you want to divide and leave it divided (no float, keep the fraction)
  • has symbols
  • arrays are typed, but can contain more than one type (will switch from char to any, for example)
  • commas are required for lists, arrays, etc (boo)
  • tuples: fixed sized bags of values, typed according to what they hold
  • arrays carry around their dimensionality (will be important for matrix-type ops later on)
  • has dictionaries as well
  • hmm: typeof({:foo => 5}) -> vector syntax is discontinued
  • Dicts have to be explicitly built now: Dict(:foo => 5) is the equivalent
  • XOR operator with $
  • bits to see the binary of a value
  • can assign to multiple variables at once with commas (like python)
  • trying to access an undefined key in a dict throws an error
  • in can check membership of arrays or iterators, but not dictionaries
  • but: can check for key and value in dict using in + pair of key, value: in(:a => 1, explicit)
  • book’s syntax of using tuple for the search is incorrect
  • julia docs are really…not helpful :/
  • book’s syntax for set construction is also wrong
  • nothing in the online docs to correct it
  • (of course, nothing in the online docs to correct my Dict construction syntax, either)
  • can construct Set with: Set([1, 2, 3])
  • arrays are typed (Any for multiple types)
  • array indexes start at 1, not 0 (!) [follows math here]
  • array slices include the ending index
  • can mutate index by assigning to existing index, but assigning to non-existing index doesn’t append to the array, throws error
  • array notation is row, column
  • * will do matrix multiplication (means # of rows of first has to match # of columns of second)
  • regular element-wise multiplication needs .*
  • need a transpose? just add ‘
  • very much like linear algebra; baked-in
  • dictionaries are typed, will throw error if you try to add key/value to them that doesn’t match the types it was created with
  • BUT: can merge a dict with a dict with different types, creates a new dict with Any to hold the differing types (keys or values)

Day Two

  • if..elseif…end
  • if check has to be a boolean; won’t coerce strings, non-boolean values to booleans (nice)
  • reference vars inside of strings with $ prefix: println(“$a”)
  • has user-defined types
  • can add type constraints to user-defined type fields
  • automatically gets constructor fn with the same name as the type and arguments, one per field
  • subtype only one level
  • abstract types are just ways to group other types
  • no more super(), use supertype() -> suggested by compiler error message, which is nice
  • functions return value of last expression
  • … to get a collection of args
  • +(1, 2) -> yields 3, operators can be used as prefix functions
  • … will expand collection into arguments for a function
  • will dispatch function calls based on the types of all the arguments
  • type on pg 208: int() doesn’t exist, it’s Int()
  • WARNING: Base.ASCIIString is deprecated, use String instead.
  • no need to extend protocols or objects, classes, etc to add new functions for dispatching on core types: can just define the new functions, wherever you like, julia will dispatch appropriately
  • avoids problem with clojure defmulti’s, where you have to bring in the parent lib all the time
  • julia has erlang-like processes and message-passing to handle concurrency
  • WARNING: remotecall(id::Integer,f::Function,args…) is deprecated, use remotecall(f,id::Integer,args…) instead.
  • (remotecall arg order has changed)
  • randbool -> NOPE, try rand(Bool)
  • looks like there’s some overhead in using processes for the first time; pflip_coins times are double the non-parallel version at first, then are reliably twice as fast
  • julia founders answered the interview questions as one voice, with no distinction between them
  • whole section in the julia manual for parallel computing

Day Three

  • macros are based off of lisp’s (!)
  • quote with :
  • names fn no longer exists (for the Expr type, just fine for the Module type)
  • use fieldnames instead
  • unquote -> $
  • invoke macro with @ followed by the args
  • Pkg.add() will fetch directly into a running repl
  • hmm…installs homebrew without checking if it’s on your system already, or if you have it somewhere else
  • also doesn’t *ask* if it’s ok to install homebrew
  • not cool, julia, not cool
  • even then, not all dependencies installed at the time…still needed QuartzIO to display an image
  • view not defined
  • ImageView.view -> deprecated
  • imgshow does nothing
  • docs don’t help
  • hmm…restarting repl seems to have fixed it…window is hidden behind others
  • img no longer has data attribute, is just the pixels now
  • rounding errors means pixels != pixels2
  • ifloor -> floor(Int64, val) now
  • works!

Seven More Languages in Seven Weeks: Elixir

So frustrating. I had high hopes going in that Elixir might be my next server-side language of choice. It’s built on the Erlang VM, after all, so concurrency should be a breeze. Ditto distributed applications and fault-tolerance. All supposedly wrapped in a more digestible syntax than Erlang provides.

Boy, was I misled.

The syntax seems to be heavily Ruby-influenced, in a bad way. There’s magic methods, black box behavior, and OOP-style features built in everywhere.

The examples in this chapter go deeply into this Ruby-flavored world, and skip entirely over what I thought were the benefits to the language. If Elixir makes writing concurrent, distributed applications easier, I have no idea, because this book doesn’t bother working examples that highlight it.

Instead, the impression I get is that this is a way to write Ruby in Erlang, an attempt to push OOP concepts into the functional programming world, resulting in a hideous language that I wouldn’t touch with a ten-foot-pole.

I miss Elm.

Day One

  • biggest influences: lisp, erlang, ruby
  • need to install erlang *and* elixir
  • both available via brew
  • syntax changing quickly, it’s a young language
  • if do:
  • IO.puts for println
  • expressions in the repl always have a return value, even if it’s just :ok
  • looks like it has symbols, too (but they’re called atoms)
  • tuples: collections of fixed size
  • can use pattern matching to destructure tuples via assignment operator
  • doesn’t allow mutable state, but can look like it, because compiler will rename vars and shuffle things around for you if you assign something to price (say) multiple times
  • weird: “pipes” |> for threading macros
  • dots and parens only needed for anonymous functions (which can still be assigned to a variable)
  • prints out a warning if you redefine a module, but lets you do it
  • pattern matching for multiple functions definition in a single module (will run the version of the function that matches the inputs)
  • can define one module’s functions in terms of another’s
  • can use when conditions in function def as guards to regulate under what inputs the function will get run
  • scripting via .exs files, can run with iex
  • put_in returns an updated copy of the map, it doesn’t update the map in place
  • elixir’s lists are linked lists, not arrays!
  • char lists are not strings: dear god
  • so: is_list “string” -> false, but is_list ‘string’ -> true (!)
  • wat
  • pipe to append to the head
  • when destructuring a list, the number of items on each side have to match (unless you use the magic pipe)
  • can use _ for matching arbitrary item
  • Enum for processing lists (running arbitrary functions on them in different ways, like mapping and reducing, filtering, etc)
  • for comprehensions: a lot like python’s list comprehensions; takes a generator (basically ways to pull values from a list), an optional filter (filter which values from the list get used), and a function to run on the pulled values
  • elixir source is on github

Day Two

  • mix is built in to elixir, installing the language installs the build tool (nice)
  • basic project template includes a gitignore, a readme, and test files
  • source files go in lib, not src
  • struct: map with fixed set of fields, that you can add behavior to via functions…sounds like an object to me :/
  • iex -S mix to start iex with modules from your project
  • will throw compiler errors for unknown keys, which is nice, i guess?
  • since built on the erlang vm, but not erlang, we can use macros, which get expanded at compile time (presumably, to erlang code)
  • should is…well…kind of a silly macro
  • __using__ just to avoid a fully-qualified call seems…gross…and too implicit
  • and we’ve got to define new macros to override compile-time behavior? i…i can’t watch
  • module attributes -> compile-time variables -> object attributes by another name?
  • use, __using__, @before_compile -> magic, magic everywhere, so gross
  • state machine’s “beautiful syntax” seems more like obscure indirection to me
  • can elixir make me hate macros?
  • whole thing seems like…a bad example. as if the person writing it is trying to duplicate OOP-style inheritance inside a functional language.
  • elixir-pipes example from the endnotes (github project) is much better at showing the motivation and usage of real macros

Day Three

  • creator’s main language was Ruby…and it shows :/
  • spawn returns the process id of the underlying erlang process
  • pattern matching applies to what to do with the messages a process receives via its inbox
  • can write the code handling the inbox messages *after* the messages are sent (!)
  • task -> like future in clojure, can send work off to be done in another process, then later wait for the return value
  • use of Erlang’s OTP built into Elixir’s library
  • construct the thing with start_link, but send it messages via GenServer…more indirection
  • hmm…claims it’s a “fully distributed server”, but all i see are functions getting called that return values, no client-server relationship here?
  • final example: cast works fine, but call is broken (says process not alive; same message regardless of what command sent in (:rent, :return, etc)
  • oddly enough, it works *until* we make the changes to have the supervisor run everything for us behind the scenes (“like magic!”)
  • endnotes say we learned about protocols, but they were mentioned only once, in day two, as something we should look up on our own :/
  • would have been nicer to actually *use* the concurrency features of language, to, idk, maybe use all the cores on your laptop to run a map/reduce job?

Seven More Languages in Seven Weeks: Elm

Between the move and the election and the holidays, took me a long time to finish this chapter.

But I’m glad I did, because Elm is — dare I say — fun?

The error messages are fantastic. The syntax feels like Haskell without being as obtuse.  Even the package management system just feels nice.

A sign of how much I liked working in Elm: the examples for Day Two and Three of the book were written for Elm 0.14, using a concept called signals. Unfortunately, signals were completely removed in Elm 0.17 (!). So to get the book examples working in Elm 0.18, I had to basically rebuild them. Which meant spending a lot of time with the (admittedly great) Elm tutorial and trial-and-erroring things until they worked again.

None of which I minded because, well, Elm is a great language to work in.

Here’s the results of my efforts:

And here’s what I learned:

Day One

  • haskell-inspired
  • elm-installer: damn, that was easy
  • it’s got a repl!
  • emacs mode also
  • types come back with all the values (expression results)
  • holy sh*t: “Maybe you forgot some parentheses? Or a comma?”
  • omg: “Hint: All elements should be the same type of value so that we can iterate through the list without running into unexpected values.”
  • type inferred: don’t have to explicitly declare the type of every variable
  • polymorphism via type classes
  • single-assignment, but the repl is a little looser
  • pipe syntax for if statement in book is gone in elm 0.17
  • case statement allows pattern matching
  • case statement needs the newlines, even in the repl (use `\`)
  • can build own complex data types (but not type classes)
  • case also needs indentation to work (especially if using result for assignment in the repl)
  • records: abstract types for people without beards
  • changing records: use `=` instead of `<-`: { blackQueen | color = White }
  • records look like they’re immutable now, when they weren’t before? code altering them in day one doesn’t work
  • parens around function calls are optional
  • infers types of function parameters
  • both left and right (!) function composition <| and |>
  • got map and filter based off the List type (?)
  • no special syntax for defining a function versus a regular variable, just set a name equal to the function body (with the function args before the equal sign)
  • head::tail pattern matching in function definition no longer works; elm is now stricter about requiring you to define all the possible inputs, including the empty list
  • elm is a curried language (!)
  • no reduce: foldr or foldl
  • have to paren the infix functions to use in foldr: List.foldr (*) 1 list
  • hard exercise seems to depend on elm being looser than it is; afaict, it won’t let you pass in a list of records with differing fields (type volation), nor will it let you try to access a field that isn’t there (another type violation)

Day Two

  • section is built around signals, which were removed in Elm 0.17 (!)
  • elm has actually deliberately moved away from FRP as a paradigm
  • looks like will need to completely rewrite the sample code for each one as we go…thankfully, there’s good examples in the elm docs (whew!)
  • [check gists for rewritten code]
  • module elm-lang/keyboard isn’t imported in the elm online editor by default anymore

Day Three

  • can fix the errors from loading Collage and Element into main by using toHtml method of the Collage object
  • elm-reactor will give you a hot-updated project listening on port 8000 (so, refresh web page of localhost:8000 and get updated view of what your project looks like)
  • error messages are very descriptive, can work through upgrading a project just by following along (and refreshing alot)
  • critical to getting game working: https://ohanhi.github.io/base-for-game-elm-017.html (multiple subscriptions)

The Problem with Programmer Interviews

You’re a nurse. You go in to interview for a new job at a hospital. You’re nervous, but confident you’ll get the job: you’ve got ten years of experience, and a glowing recommendation from your last hospital.

You get to the interview room. There must be a mistake, though. The room number they gave you is an operating room.

You go in anyway. The interviewer greets you, clipboard in hand. He tells you to scrub up, join the operation in progress.

“But I don’t know anything about this patient,” you say. “Or this hospital.”

They wave away your worries. “You’re a nurse, aren’t you? Get in there and prove it.”

….

You’re a therapist. You’ve spent years counseling couples, helping them come to grips with the flaws in their relationship.

You arrive for your interview with a new practice. They shake your hand, then take you into a room where two men are screaming at each other. Without introducing you, the interviewer pushes you forward.

“Fix them,” he whispers.

You’re a pilot, trying to get a better job at a rival airline. When you arrive at your interview, they whisk you onto a transatlantic flight and sit you in the captain’s chair.

“Fly us there,” they say.

You’re a software engineer. You’ve been doing it for ten years. You’ve seen tech fads come and go. You’ve worked for tiny startups, big companies, and everything in-between. Your last gig got acquired, which is why you’re looking for a new challenge.

The interviewers — there’s three of them, which makes you nervous — smile and shake your hand. After introducing themselves, they wave at the whiteboard behind you.

“Code for us.”

 

Seven More Languages in Seven Weeks: Factor

Continuing on to the next language in the book: Factor.

Factor is…strange, and often frustrating. Where Lua felt simple and easy, Factor feels simple but hard.

Its concatenative syntax looks clean, just a list of words written out in order, but reading it requires you to keep a mental stack in your head at all times, so you can predict what the code does.

Here’s what I learned:

Day One

  • not functions, words
  • pull and push onto the stack
  • no operator precedence, the math words are applied in order like everything else
  • whitespace is significant
  • not anonymous functions: quotations
  • `if` needs quotations as the true and false branches
  • data pushed onto stack can become “out of reach” when more data gets pushed onto it (ex: store a string, and then a number, the number is all you can reach)
  • the `.` word becomes critical, then, for seeing the result of operations without pushing new values on the stack
  • also have shuffle words for just this purpose (manipulating the stack)
  • help documentation crashes; no listing online for how to get word docs in listener (plenty for vocab help, but that doesn’t help me)
  • factor is really hard to google for

Day Two

  • word definitions must list how many values they take from the stack and how many they put back
  • names in those definitions are not args, since they are arbitrary (not used in the word code itself)
  • named global vars: symbols (have get and set; aka getters and setters)
  • standalone code imports NOTHING, have to pull in all needed vocabularies by hand
  • really, really hate the factor documentation
  • for example, claims strings implement the sequence protocol, but that’s not exactly true…can’t use “suffix” on a string, for example

Day Three

  • not maps, TUPLES
  • auto-magically created getters and setters for all
  • often just use f for an empty value
  • is nice to be able to just write out lists of functions and not have to worry about explicit names for their arguments all over the place
  • floats can be an issue in tests without explicit casting (no types for functions, just values from the stack)
  • lots of example projects (games, etc) in the extra/ folder of the factor install

Seven More Languages in Seven Weeks: Lua

Realized I haven’t learned any new programming languages in a while, so I picked up a copy of Seven More Languages in Seven Weeks.

Each chapter covers a different language. They’re broken up into ‘Days’, with each day’s exercises digging deeper into the language.

Here’s what I learned about the first language in the book, Lua:

Day One

Just a dip into basic syntax.

  • table based
  • embeddable
  • whitespace doesn’t matter
  • no integers, only floating-point (!)
  • comparison operators will not coerce their arguments, so you can’t do =42 < ’43’
  • functions are first class
  • has tail-call-optimization (!)
  • extra args are ignored
  • omitted args just get nil
  • variables are global by default (!)
  • can use anything as key in table, including functions
  • array indexes start at 1 (!)

Day Two

Multithreading and OOP.

  • no multithreading, no threads at all
  • coroutines will only ever run on one core, so have to handle blocking and unblocking them manually
  • explicit over implicit, i guess?
  • since can use functions as values in tables, can build entire OO system from scratch using (self) passed in as first value to those functions
  • coroutines can also get you memoization, since yielding means the state of the fn is saved and resumed later
  • modules: can choose what gets exported, via another table at the bottom

Day Three

A very cool project — build a midi player in Lua with C++ interop — that was incredibly frustrating to get working. Nothing in the chapter was helpful. Learned more about C++ and Mac OS X audio than Lua.

  • had to add Homebrew’s Lua include directory (/usr/local/Cellar/lua/5.2.4_3/include) into include_directories command in CMakeLists.txt file
  • when compiling play.cpp, linker couldn’t find lua libs, so had to invoke the command by hand (after reading ld manual) with brew lua lib directory added to its search path via -L
  • basically, add this to CMakeFiles/play.dir/link.txt: -L /usr/local/Cellar/lua/5.2.4_3/lib -L /usr/local/Cellar/rtmidi/2.1.1/lib
  • adding those -L declarations will ensure make will find the right lib directories when doing its ld invocation (linking)
  • also had to go into the Audio Midi Setup utility and set the IAC Driver to device is online in order for any open ports to show up
  • AND then needed to be sure was running the Simplesynth application with the input set to the IAC Driver, to be able to hear the notes

Follow the Tweeting Bot

I have a problem.

No, not my fondness for singing 80s country in a bad twang during karaoke.

I mean a real, nerd-world problem: I have too many books to read.

I can’t leave any bookstore without buying at least one. For a good bookstore, I’ll walk out with half a dozen or more, balancing them in my arms, hoping none of them fall over.

I get them home and try to squeeze them into my bookshelf of “books I have yet to read” (not to be confused with my “books I’ve read and need to donate” or “books I’ve read and will re-read someday when I have the time” shelves). That shelf is full, floor to ceiling.

My list of books to read is already too long for me to remember them all. And that’s not counting the ones I have sitting in ebook format, waiting on my Kobo or iPhone for me to tap their cover art and dive in.

Faced with so much reading material, so many good books waiting to be read, my question is this: What do I read next?

I could pick based on mood. But that usually means me sitting in front of my physical books, picking out the one that grabs me. I could pick based on which ones I’ve bought most recently, which would probably narrow things down to just my ebooks.

But I want to be able to choose from all of my books, physical and virtual, at any time.

So I wrote a bot to help me.

It listens to my twitter stream for instructions. When I give it the right command, it pulls down my to-read shelf from Goodreads (yes, I put all of my books, real and electronic, into Goodreads. yes, it took much longer than I thought it would), ranks them in order of which ones I should read first, and then tweets back to me the top 3.

I’ve been following its recommendations for about a month now, and so far, it’s working. Footsteps in the Sky was great. Data and Goliath was eye-opening. The Aesthetic of Play changed the way I view art and games.

Now, if only I could train it to order books for me automatically…