Macro #clojureconj

Similar documents
Lazytest Better Living Through Protocols. Stuart Sierra. Clojure NYC April 15, 2010

Clojure Lisp for the Real clojure.com

What if Type Systems were more like Linters?

Introduction Basics Concurrency Conclusion. Clojure. Marcel Klinzing. December 13, M. Klinzing Clojure 1/18

CPL 2016, week 10. Clojure functional core. Oleg Batrashev. April 11, Institute of Computer Science, Tartu, Estonia

The Curious Clojureist

Clojure for OOP folks Stefan innoq

Clojure is. A dynamic, LISP-based. programming language. running on the JVM

June 27, 2014 EuroClojure 2014 Krakow, Poland. Components. Just Enough

Clojure Lisp for the Real #clojure

Clojure Distilled. Immutable

Symbols. abstractions, implementing, 270 through indirection, 77 with macros, 183 abstract syntax tree (AST), 149

.consulting.solutions.partnership. Clojure by Example. A practical introduction to Clojure on the JVM

A Brief Introduction to Common Lisp

Lecture #5 Kenneth W. Flynn RPI CS

CS 3 Introduction to Software Engineering. 3: Exceptions

CS112 Lecture: Exceptions and Assertions

Exceptions. CSC207 Winter 2017

Project Compiler. CS031 TA Help Session November 28, 2011

CS 360 Programming Languages Interpreters

CSC207H: Software Design. Exceptions. CSC207 Winter 2018

Chapter 3 Java Exception

clojure & cfml sitting in a tree sean corfield world singles

Tools for Unit Test - JUnit

CS112 Lecture: Exceptions. Objectives: 1. Introduce the concepts of program robustness and reliability 2. Introduce exceptions

Programming II (CS300)

Week 2: The Clojure Language. Background Basic structure A few of the most useful facilities. A modernized Lisp. An insider's opinion

Write a procedure powerset which takes as its only argument a set S and returns the powerset of S.

Exceptions Handling Errors using Exceptions

Below are example solutions for each of the questions. These are not the only possible answers, but they are the most common ones.

Mastering Python Decorators

Common LISP-Introduction

CSE 331 Software Design & Implementation

Programs as data first-order functional language type checking

Custom Specializers in Object-Oriented Lisp

CS558 Programming Languages

POETRY OF PROGRAMMING CODE READING EXERCISES IN CLOJURE V

CS558 Programming Languages


CMSC131. Exceptions and Exception Handling. When things go "wrong" in a program, what should happen.

1.3.4 case and case* macro since 1.2. Listing Conditional Branching, Fast Switch. Listing Contract

INF4820. Common Lisp: Closures and Macros

A PROGRAM IS A SEQUENCE of instructions that a computer can execute to

BUILDING DECLARATIVE GUIS WITH CLOJURE, JAVAFX AND FN-FX DR. NILS BLUM-OESTE

CS558 Programming Languages

Robot Programming with Lisp

Overview. finally and resource cleanup

Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming.

Tools for Unit Test JUnit

Object Oriented Programming. Week 7 Part 1 Exceptions

a little more on macros sort of like functions, but..

Chapter 11: Exception Handling

Exceptions in Java

CS61A Discussion Notes: Week 11: The Metacircular Evaluator By Greg Krimer, with slight modifications by Phoebus Chen (using notes from Todd Segal)

Relation Overriding. Syntax and Semantics. Simple Semantic Domains. Operational Semantics

Principles of Programming Languages, 2

CS450: Structure of Higher Level Languages Spring 2018 Assignment 7 Due: Wednesday, April 18, 2018

CSE413: Programming Languages and Implementation Racket structs Implementing languages with interpreters Implementing closures

Clojure. A (not-so-pure) functional approach to concurrency. Paolo Baldan Linguaggi per il Global Computing AA 2016/2017

Programming Languages

Functional Programming

Michiel DomCode, May 26th 2015

Seminar on Languages for Scientific Computing Aachen, 6 Feb Navid Abbaszadeh.

Next: What s in a name? Programming Languages. Data model in functional PL. What s in a name? CSE 130 : Fall Lecture 13: What s in a Name?

PLanCompS. Peter D Mosses Swansea University. SSLF12: Summer School on Language Frameworks Sinaia, Romania, July 2012

They are a block of code plus the bindings to the environment they came from (Ragusa Idiom / function object).

Concepts of programming languages

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

Exceptions and assertions

Late Binding; OOP as a Racket Pattern

CSCI B522 Lecture 11 Naming and Scope 8 Oct, 2009

Chapter 14. Exception Handling and Event Handling ISBN

TAIL RECURSION, SCOPE, AND PROJECT 4 11

Data structures. Priority queues, binary heaps. Dr. Alex Gerdes DIT961 - VT 2018

Lecture 20. Java Exceptional Event Handling. Dr. Martin O Connor CA166

PIC 20A Exceptions. Ernest Ryu UCLA Mathematics. Last edited: November 27, 2017

Meet the Macro. a quick introduction to Lisp macros. Patrick Stein / TC Lisp Users Group /

Some Naughty Bits. Jeremy Brown. January 7-8, 2003

Exceptions. References. Exceptions. Exceptional Conditions. CSE 413, Autumn 2005 Programming Languages

Designing Robust Classes

This tutorial is designed for all those software professionals who are keen on learning the basics of Clojure and how to put it into practice.

COPYRIGHTED MATERIAL INDEX. Symbols and Numerals. # in URL, 146

Chapter 10. Exception Handling. Java Actually: A Comprehensive Primer in Programming

CS 61B Data Structures and Programming Methodology. July 7, 2008 David Sun

CSC 148 Lecture 3. Dynamic Typing, Scoping, and Namespaces. Recursion

Object Oriented Programming (OOP)

Every language has its own scoping rules. For example, what is the scope of variable j in this Java program?

6.037 Lecture 4. Interpretation. What is an interpreter? Why do we need an interpreter? Stages of an interpreter. Role of each part of the interpreter

Today. CSE341: Programming Languages. Late Binding in Ruby Multiple Inheritance, Interfaces, Mixins. Ruby instance variables and methods

Reagent. a ClojureScript interface to React. React Amsterdam Meetup 12 Feb. 2015

To Think About. MyClass.mogrify(new int[] { 1, 2, 4, 6 }));

Exceptions. CSE 142, Summer 2002 Computer Programming 1.

Exceptions. Readings and References. Exceptions. Exceptional Conditions. Reading. CSE 142, Summer 2002 Computer Programming 1.

Michael Fogus Chris Houser FOREWORD BY STEVE YEGGE MANNING

OCaml Data CMSC 330: Organization of Programming Languages. User Defined Types. Variation: Shapes in Java

UNIT 3

EXCEPTIONS. Objectives. The try and catch Statements. Define exceptions. Use try, catch and finally statements. Describe exception categories

Programming II (CS300)

NST: A Unit Test Framework for Common Lisp

Structured bindings with polymorphic lambas

Transcription:

Macro Club @stuartsierra #clojureconj

500 sq ft

I ( )

If it seems simple, you're probably doing it wrong.

You can pry EMACS from my cold, dead fingers.

The First Rule of Macro Club You do not write macros.

Macros are harder to write than ordinary Lisp functions, and it's considered to be bad style to use them when they're not necessary. -Paul Graham, Beating the Averages

I `~@

clojure.test (is (= 4 (+ 2 2))) true

clojure.test (macroexpand '(is (= 4 (+ 2 2)))) (try (let [values (list 4 (+ 2 2)) result (apply = values)] (if result (do-report {:type :pass,...}) (do-report {:type :fail, :actual values,...})) result) (catch java.lang.throwable t (do-report {:type :error, :actual t,...})))

clojure.test (macroexpand '(is (thrown? ArithmeticException (/ 1 0)))) (try (try (/ 1 0) (do-report {:type :fail, :actual nil,...}) (catch ArithmeticException e (do-report {:type :pass, :actual e,...}) e)) (catch java.lang.throwable t (do-report {:type :error, :actual t,...})))

clojure.test (thrown? ArithmeticException (/ 1 0)))) #<CompilerException java.lang.exception: Unable to resolve symbol: thrown? in this context>

clojure.test (defmacro is [message form] `(try ~(assert-expr message form) (catch Throwable t# (do-report {:type :error,...})))) (defmulti assert-expr (fn [msg form] (first form))) (defmethod assert-expr '= [msg form]...) (defmethod assert-expr 'thrown? [msg form]...)

The Second Rule of Macro Club You do not write macros... that violate expectations of normal code behavior.

Lazytest github.com/stuartsierra/lazytest

The Third Rule of Macro Club If this is your first time, you must write a macro.

lazytest.expect (defmacro expect ([expr] `(expect nil ~expr)) ([docstring expr] {:pre [(or (string? docstring) (nil? docstring))]} (if (function-call? expr) ;; Normal function call `(let [f# ~(first expr) args# (list ~@(rest expr)) result# (apply f# args#)] (or result# (throw (ExpectationFailed. (merge '~(meta &form) '~(meta expr) {:form '~expr :locals ~(local-bindings &env) :evaluated (list* f# args#) :result result# :file ~*file* :ns '~(ns-name *ns*)} ~(when docstring {:doc docstring})))))) ;; Unknown type of expression `(let [result# ~expr] (or result# (throw (ExpectationFailed. (merge '~(meta &form) '~(meta expr) {:form '~expr :locals ~(local-bindings &env) :result result# :file ~*file* :ns '~(ns-name *ns*)} ~(when docstring {:doc docstring})))))))))

lazytest.expect (expect (= 4 (+ 2 2))) ;; If that's not true... (throw (ExpectationFailed. {:form ; what you passed in :evaluated ; each component, evaluated :result ; return value :locals ; local bindings :doc ; optional docstring :file ; file name :line ; line number :ns ; namespace name }))

lazytest.expect package lazytest; public class ExpectationFailed extends AssertionError { public final Object reason; public ExpectationFailed(Object reason) { this.reason = reason; } }

Test Case Something that can be run. Result: pass or fail

Suite Collection of Test Cases and/or other Suites.

clojure.test Grouping (deftest test-one...) (deftest test-two...) (deftest my-test-group (test-one) (test-two))

I Protocols

(defprotocol Testable (run-tests [this] "Run tests in this suite.")) (deftype Suite [children] Testable (run-tests [this] (map run-tests children))) (deftype TestCase [f] Testable (run-tests [this] (try (f)...)))

The Fourth Rule of Macro Club Don't think object-oriented.

Objects are a poor man's closures. -Lisp dude Closures are a poor man's objects. -OOP dude

(defprotocol Testable (run-tests [this] "Run tests in this suite.")) (deftype Suite [children] Testable (run-tests [this] (map run-tests children))) (deftype TestCase [assertion] Testable (run-tests [this] (try (assertion)...)))

Test Case Something that can be run. Result: pass or fail

Test Case (fn [] (expect...))

Suite Collection of Test Cases and/or other Suites.

Suite (fn [] (seq... test cases...... and/or suites...))

Suite (defmacro describe [doc & children] `(fn [] (with-meta (list ~@children) {:doc ~doc :file... :line...})))

Test Case (defmacro it [docstring expr] `(with-meta (fn [] (expect ~expr)) {:doc ~docstring :file... :line...}))

DSL (describe "A list" (it "is a sequence" (seq? (list))) (it "is countable" (= 3 (count (list 1 2 3)))) (it "grows at the front" (= (list 2 1) (cons 2 (list 1)))))

Context... set up some state...... make assertions about it...... clean up...

clojure.test Fixtures (defn my-fixture [test-fn]... stuff that happens before... (test-fn)... stuff that happens after...) (use-fixtures :each my-fixture)

clojure.test Fixtures (declare *state*) (defn my-fixture [test-fn] (binding [*state*...setup...] (test-fn)... cleanup state...))

The Fifth Rule of Macro Club No shirt, No shoes, No dynamic scope.?

Context... set up some state...... make assertions about it...... clean up...

Context (defprotocol Context (setup [this] "Setup and return some state") (teardown [this] "Clean up state"))

System Property Context (deftype PropertyContext [name value] Context (setup [this]... set Java system property...) (teardown [this]... restore original value...))

Temp File Context (deftype FileContext [] Context (setup [this]... create temporary file...) (teardown [this]... delete file...))

Alter Var Root Context (deftype GlobalStubContext [var value] Context (setup [this]... set root binding of var...) (teardown [this]... restore original value...))

Context: (setup cntxt) Test Case: state (fn [] (expect (= state...))) Context: (teardown cntxt)

Context: (setup cntxt) Test Case: state (fn [state] (expect (= state...))) Context: (teardown cntxt)

DSL (describe "A list" (it "is a sequence" (seq? (list))) (it "is countable" (= 3 (count (list 1 2 3)))) (it "grows at the front" (= (list 2 1) (cons 2 (list 1)))))

Stateful Context (deftype StatefulContext [...] Context (setup [this]... create state...) (teardown [this]... destroy state...) clojure.lang.ideref (deref [this]... return state...))

Stateful Context (stateful-fn-context (fn []... create & return state...) (fn [state]... destroy state...))

Stateful Context (def cntxt (stateful-fn-context...)) (setup cntxt) ;; get the state: @cntxt (teardown cntxt)

DSL (def cntxt (stateful-fn-context...)) (describe "..." (with [cntxt] (it "..."... @cntxt...) (it "..."... @cntxt...)))

The Sixth Rule of Macro Club You don't create new scoping rules.

Bullet Points Build abstractions on Clojure's existing types Functions are the most powerful abstraction Use macros for syntactic sugar Don't break expectations of normal code Don't think OOP

#clojureconj @stuartsierra stuartsierra.com clojure.com github.com/stuartsierra Practical Clojure