Gershwin

Thank You,

Etymology Man

Thank you,

Family

Why?

Extension to Clojure

What makes a language

extension-worthy?

How far until

we break it?

Language Mastery

  • Human

    • Phonetics/Phonology
  • Programming

    • Syntax

r

Spanish, Russian, Arabic

German, French

Japanese

English

Clojure Syntax

                "string literals"

                :keywords-or-symbols-depending-on-your-background

                'a-lisp-symbol

                42

                1/3

                #"[Rr]egular Expres{2}ions"

                #'clojure.core/var

Clojure Syntax

                 ()        Function/macro/special form call

                '()        Quoted form, list

                 []        Vectors

                 {}        Hash-maps

                #{}        Sets

Gershwin Additions

  • No parens needed to call/invoke
  • Functions are called 'words'
  • Use : to define words
  • Anonymous functions are called 'quotations'
  • Use #[ ] to write quotations
  • Gershwin words and Clojure functions can share names
  • Use #*example.ns/var to reference a Gershwin var

Gershwin Implementation

  • clojure.lang.LispReader
    • Reader macros #[ ] and #*
    • Parsing : followed by space
  • clojure.lang.LineNumberingPushbackReader
    • Increase buffer
    • Differentiate : a-word ... from :a-keyword

Language Mastery

  • Human

    • Phonetics/Phonology
    • Words/Phrases
  • Programming

    • Syntax
    • Functions, Objects/Methods

Clojure Functions

                 (+ 2 2)                 ;=> 4
                 (get {:foo "bar"} :foo)                 ;=> "bar"
                 ({:foo "bar"} :foo)                 ;=> "bar"
                 (:foo {:foo "bar"})                 ;=> "bar"
                 (apply hash-map [:a 1 :b 2])                 ;=> {:a 1, b: 2}
                 (map #(* % 2) [1 2 3 4])                 ;=> (2 4 6 8)

Clojure Functions

                 (def my-data (atom 42))                 (defn times-2 [x] (* x 2))                 (defn times-n [n] (fn [x] (* x n)))
                 ((times-n 2) 4)                 ;=> 8
                 (map (times-n 2) [1 2 @my-data 3])                 ;=> [1 2 84 6]

Gershwin Words

                 2 2 +                 ;; 4
                 :foo {:foo "bar"} get                 ;; "bar"
                 :foo {:foo "bar"} apply                 ;; "bar"
                 {:foo "bar"} :foo apply                 ;; "bar"
                 [:a 1 :b 2] hash-map*                 ;; {:a 1, b: 2}
                 [1 2 3 4] #[ 2 * ] map                 ;; (2 4 6 8)

Gershwin Words

                 (def my-data (atom 42))                 : times-2 [n -- n] 2 * .
                 4 times-2                 ;=> 8
                 [1 2 @my-data 3] #[ 2 * ] map                 ;=> [1 2 84 6]
                 [1 2 @my-data 3] #[ times-2 ] map                 ;=> [1 2 84 6]

Usually,

it's just backwards

Chopsticks

                             (map #(* % 2) [1 2 3 4])
           [1 2 3 4] #[ 2 * ] map
                        ;; (2 4 6 8)

Chopsticks

                             (assoc {:lang "gershwin"}
                                    :parent 
                                    "clojure")
           "clojure"
           :parent
           {:lang "gershwin"} assoc
                 ;; {:lang "gershwin", :parent "clojure"}

Two steps forward…

                             (if (= answer 42)
                               :ok
                               :bad)
                    answer 42 =
                    #[ :ok ]
                    #[ :bad ] if
                          ;; :ok

Some things

زوجتي ٢٠٠٩

read left-to-right

Greetings & Niceties

Comment allez-vous?

Будь здоров!

أهلا وسهلا

Does my vector have this item?

(some #{:c} [:a :b :c])

Gershwin Compiler Extensions

  • gershwin.main
    • Entry-point for REPL, loading files
    • REPL prompt prints data stack
  • clojure.lang.Compiler
    • Compiler.load() takes one extra argument
    • Supports both Gershwin and non-Gershwin modes
    • Use of () allows Clojure interop

Gershwin Compiler Extensions

  • Evaluation
    • Not a word ==> wrap to conj onto stack
    • Word ==> wrap to invoke
    • Clojure function-turtles all the way down
  • Stack
    • Implements IPersistentStack
    • Uses Clojure vector under the covers
    • Stored as dynamic var in gershwin.core namespace

Stack-based Approach

  • Functions are never explicitly passed arguments
  • Instead take an implicit stack, maintained by the language
  • Totally insane

But

  • Levels of succinctness and elegance achieved…stunning
  • Vigorous factoring of words (think functions) into smaller words
  • Stack-manipulation primitives signal the need for factoring

Factor

Factor belongs to the family of concatenative languages…a Factor program is a series of words (functions) that manipulate a stack of references to dynamically-typed values.

Stack Manipulation

                 user=> 1 2 3                 --- Data Stack:
                  1
                  2
                  3
                 user=> drop                 --- Data Stack:
                  1
                  2
                 user=> swap                 --- Data Stack:
                  2
                  1
                 user=> dup                 --- Data Stack:
                  2
                  1
                  1

Stack Manipulation

                 user=> 1 2 3 rot                 --- Data Stack:
                  2
                  3
                  1
                 user=> nip                 --- Data Stack:
                  2
                  1
                 user=> over                 --- Data Stack:
                  2
                  1
                  2
                 user=> 1 2 3 pick                 --- Data Stack:
                  1
                  2
                  3
                  1

Dataflow Combinators

"Higher-order stack manipulation"

Dataflow Combinators

  • Preserving: Temporarily hide values on stack
  • Cleave: Apply multiple quotations to single value
  • Spread: Apply multiple quotations to multiple values
  • Apply: Apply single quotation to multiple values

Preserving Combinators

                 user=> 4 5 #[ 2 * ] dip                 --- Data Stack:
                  8
                  5
                 user=> 4 5 #[ 2 * ] keep                 --- Data Stack:
                  4
                  10
                  5

Cleave Combinators

                 user=> 2 #[ 2 * ] #[ 3 * ] bi                 --- Data Stack:
                  4
                  6
                 user=> 2 #[ 2 * ] #[ 3 * ] #[ 4 * ] tri                 --- Data Stack:
                  4
                  6
                  8

Spread Combinators

                 user=> 2 3 #[ 2 * ] #[ 3 * ] bi*                 --- Data Stack:
                  4
                  9
                 user=> 2 3 4 #[ 2 * ] #[ 3 * ] #[ 4 * ] tri*                 --- Data Stack:
                  4
                  9
                  16

Apply Combinators

                 user=> 2 3 #[ 2 * ] bi&                 --- Data Stack:
                  4
                  6
                 user=> 2 3 4 #[ 2 * ] tri&                 --- Data Stack:
                  4
                  6
                  8

When Gershwin?

The most annoying thing about #Clojure for me is that sans currying, I have to design for _either_ -> or regular composition...I default to caring about ->.

— Chris Ford

Function Composition

 (def data [{:id 1 :content [{:lang "clojure"}]}
            {:id 2 :content [{:lang "gershwin"}]}])

 ((comp :lang first :content first) data)
 ;=> "clojure" 

Arrow Macro

 (def data [{:id 1 :content [{:lang "clojure"}]}
            {:id 2 :content [{:lang "gershwin"}]}])

 (-> data second :content first :lang)
 ;=> "gershwin" 

Gershwin "Arrow"

 (def data [{:id 1 :content [{:lang "clojure"}]}
            {:id 2 :content [{:lang "gershwin"}]}])

 data second :content apply first :lang apply
 ;=> "gershwin" 

Gershwin takes the -> approach

Language Mastery

  • Human

    • Phonetics/Phonology
    • Words/Phrases
    • Sentences/Paragraphs
  • Programming

    • Syntax
    • Functions, Objects/Methods
    • Modular Applications

Clojure Modularity

  • Modules: Namespaces
  • Dispatch: Multi-methods, Protocols, Interfaces
  • Flow: Functional composition, Arrow macros
  • State: Scarce

Language Mastery

  • Human

    • Phonetics/Phonology
    • Words/Phrases
    • Sentences/Paragraphs
  • Programming

    • Syntax
    • Functions, Objects/Methods
    • Modular Applications

Language Design

  • Micro Level

    • Syntax
    • Functions, Objects/Methods
  • Macro Level

    • Modular Applications

Language Design

  • Micro Level

    • Syntax
    • Functions, Objects/Methods
  • Macro Level

    • Modular Applications

Architect your program

Language Design

  • Micro Level

    • Syntax
    • Functions, Objects/Methods
  • Macro Level

    • Modular Applications

Trust your program

Micro-level Clojure

  • Functional
  • Lisp
  • Identity, State, Value, Time
  • Hosted

A language that doesn't let you affect the way it thinks is not worth growing

— Michael Fogus

Clojure ‘Extensions’

  • core.async
  • core.logic
  • core.typed
  • Datomic Datalog/Cascalog
  • Gershwin

A language that doesn’t affect the way you think about programming is not worth knowing.

— Alan Perlis

If your programming language isn't a tool for thought then you're the tool.

— Michael Fogus

When Gershwin?

Lots of -> in your Clojure

It fits your brain, or the problem

See Gershwin projects on Github

Gershwin Resources

Thank You