/matches

matching records and lambdas

Primary LanguageClojure

Matches

This little library is built on top of core.match

It exposes 4 straighforward (but useful I hope) macros:

  • deft and defc to define a type
  • fm and defm for creating and defining pattern matching lambdas

Tutorial

Add matches to your project

Put the following in your deps.edn

{pbaille/matches {:mvn/version "0.1.7-SNAPSHOT"}}

Then you can require it like this:

(ns my.app
  (:require [matches.core :as m :refer [deft defc fm defm]]))

Defining a type

(deft num [val]) ;; defines a simple record with a field 'val

It can be instanciated like this

(num 1) ;;=> (num 1)

It prints in a more concise way than default clojure record e.g (num 1)

We can access its field with normal clojure syntax.

(:val (num 1)) ;;=> 1

A predicate is available too

(num? (num 1)) ;;=> true

A type can have several fields

(deft fork [left right])

And take protocols implementation as defrecord do:

(deft myfun [f]
  clojure.lang.IFn
  (invoke [this x] ((:f this) x)))

(= 1 ((myfun identity) 1))

defm

Is defining a pattern matched function.

Where user types (defined with deft or defc) can be matched/destructured

(defm sum
  [(num x) (num y)] (num (+ x y))
  [(fork x y) z] (sum (sum x y) z)
  [x (fork y z)] (sum x (sum y z)))

(= (sum (num 1) (num 2))
   (num 3))

(= (num 10)
   (sum (fork (num 3) (fork (num 1) (num 2)))
        (num 4)))

fm (anonymous form)

(let [f (fm [x y] :a
            [x y z] :b)]
  (and (= :a (f 1 2))
       (= :b (f 1 2 3))))

Sometimes you want the whole structure, not destructured

(= ((fm [(num? x) (fork y z)] [x y z])
    ;; (num? x) is what I call a type-predicate pattern
    ;; it binds x to the whole structure
    (num 1)
    (fork 2 3))

   [(num 1) 2 3])

defm can have several arities

(defm myfun
  [0 x] :a
  [1 x] :b
  [x y] :c
  [0 x y] :d
  [x y z g] :e)

(= :a (myfun 0 42))
(= :b (myfun 1 'iop))
(= :c (myfun 2 3))
(= :d (myfun 0 :foo :bar))
(= :e (myfun 0 :foo :bar :baz))

Even variadic

(defm add
  [x] x
  [0 x] x
  [x 0] x
  [x y] (+ x y)
  [x y & xs] (reduce add x (cons y xs)))

(= 3 (add 1 2))
(= 10 (add 1 2 3 4))

You can put several variadic patterns

(defm add
  [x y & nil] (+ x y)
  [x y & xs] (apply add (add x y) xs))

(= 18 (add 3 4 5 )6)

defc

defc defines a new type, like deft.

Along with a pattern matched constructor function:

(defc duo [a b] ;; this is the same as deft, a and b are the record fields
  ;; constructor cases
  ;; each case returns the fields values
  [(num x) (num y)] [x y] ;; here x and y will be bound to a and b fields
  [(fork x _) (fork _ y)] [x y]
  [x y] [x y]
  ;; the constructor can have several arities as long as it returns the required fields values
  [(num x) (num y) z] [(+ x y) z]) 

(duo (num 1) (num 2)) ;;=> (duo 1 2)
(duo (fork :a :b) (fork :c :d)) ;;=> (duo :a :d)
(duo :what :ever) ;=> (duo :what :ever)
(duo (num 1) (num 2) 3) ;=> (duo 3 3)