• Stars
    star
    462
  • Rank 94,832 (Top 2 %)
  • Language
    Clojure
  • License
    Eclipse Public Li...
  • Created about 10 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A macro to define clojure functions with parameter pattern matching just like erlang or elixir.

Clojure CI

defun

A macro to define clojure functions with pattern matching just as erlang or elixir. It supports both clojure and clojurescript.

Usage

Dependency in leiningen:

    [defun "0.4.0"]

Basic usage

Require defun.core in clojure:

(require '[defun.core :refer [defun]])

Or refer-macros in clojurescript:

(ns cljs-test
  (:require  [defun.core :refer-macros [defun]])
(enable-console-print!)

Try to define function just like defn:

(defun hello
   "hello world"
   [name] (str "hello," name))
(hello "defun")
;; "hello,defun"

Supports variadic arguments, doc, metadata etc. as defun too. No surprises?

The fun thing is coming, let's say hi to people:

(defun say-hi
  ([:dennis] "Hi,good morning, dennis.")
  ([:catty] "Hi, catty, what time is it?")
  ([:green] "Hi,green, what a good day!")
  ([other] (str "Say hi to " other)))

Then calling say-hi with different names:

(say-hi :dennis)
;;  "Hi,good morning, dennis."
(say-hi :catty)
;;  "Hi, catty, what time is it?"
(say-hi :green)
;;  "Hi,green, what a good day!"
(say-hi "someone")
;;  "Say hi to someone"

We define functions just like Erlang's function with parameters pattern match (thanks to core.match), we don't need if,cond,case any more, that's cool!

Recursion

Let's move on, what about define a recursive function? That's easy too:

(defun count-down
  ([0] (println "Reach zero!"))
  ([n] (println n)
     (recur (dec n))))

Invoke it:

(count-down 5)
;;5
;;4
;;3
;;2
;;1
;;Reach zero!
nil

An accumulator from zero to number n:

(defun accum
  ([0 ret] ret)
  ([n ret] (recur (dec n) (+ n ret)))
  ([n] (recur n 0)))

(accum 100)
;;5050

A fibonacci function:

(defun fib
    ([0] 0)
    ([1] 1)
    ([n] (+ (fib (- n 1)) (fib (- n 2)))))

Output:

(fib 10)
;; 55

Of course it's not tail recursive, but it's really cool, isn't it?

Guards

Added a guard function to parameters:

(defun funny
  ([(N :guard #(= 42 %))] true)
  ([_] false))

(funny 42)
;;  true
(funny 43)
;; false

Another function to detect if longitude and latitude values are both valid:

(defun valid-geopoint?
    ([(_ :guard #(and (> % -180) (< % 180)))
      (_ :guard #(and (> % -90) (< % 90)))] true)
    ([_ _] false))

(valid-geopoint? 30 30)
;; true
(valid-geopoint? -181 30)
;; false

Private defun

Of course, you can use defun- to define a function that is private just as defn-

More Patterns

In fact ,the above say-hi function will be expanded to be:

(defn
 say-hi
 {:arglists '([& args])}
 [& args#]
 (clojure.core.match/match
  [(vec args#)]
  [[:dennis]]
  (do "Hi,good morning, dennis.")
  [[:catty]]
  (do "Hi, catty, what time is it?")
  [[:green]]
  (do "Hi,green, what a good day!")
  [[other]]
  (do (str "Say hi to " other))))

The argument vector is in fact a pattern in core.match, so we can use all patterns that supported by core.match.

For example, matching literals

(defun test1
    ([true false] 1)
    ([true true] 2)
    ([false true] 3)
    ([false false] 4))

(test1 true true)
;; 2
(test1 false false)
;; 4

Matching sequence:

(defun test2
    ([([1] :seq)] :a0)
    ([([1 2] :seq)] :a1)
    ([([1 2 nil nil nil] :seq)] :a2))

(test2 [1 2 nil nil nil])
;; a2

Matching vector:

(defun test3
    ([[_ _ 2]] :a0)
    ([[1 1 3]] :a1)
    ([[1 2 3]] :a2))

(test3 [1 2 3])
;; :a2

Rest Pattern, Map Pattern, Or Pattern etc.

I don't want to copy the core.match's wiki,please visit it by yourself.

fun and letfun

((fun
    ([[_ _ 2]] :a0)
    ([[1 1 3]] :a1)
    ([[1 2 3]] :a2))
  [1 2 3])
;; :a2

(letfun [(test3 ([[_ _ 2]] :a0)
                    ([[1 1 3]] :a1)
                    ([[1 2 3]] :a2))]
  (test3 [1 2 3]))
;; :a2

Criterium benchmarking

Uses the above function accum compared with a normal clojure function:

(require '[criterium.core :refer [bench]])

(defn accum-defn
    ([n] (accum-defn 0 n))
    ([ret n] (if (= n 0) ret (recur (+ n ret) (dec n)))))

(defun accum-defun
  ([0 ret] ret)
  ([n ret] (recur (dec n) (+ n ret)))
  ([n] (recur n 0)))

(bench (accum-defn 10000))
;;Evaluation count : 106740 in 60 samples of 1779 calls.
;;             Execution time mean : 578.777537 µs
;;    Execution time std-deviation : 23.354350 µs
;;   Execution time lower quantile : 552.627735 µs ( 2.5%)
;;   Execution time upper quantile : 637.001868 µs (97.5%)
;;                   Overhead used : 17.111650 ns

(bench (accum-defun 10000))
;;Evaluation count : 54660 in 60 samples of 911 calls.
;;             Execution time mean : 1.115643 ms
;;    Execution time std-deviation : 32.916487 µs
;;   Execution time lower quantile : 1.078117 ms ( 2.5%)
;;   Execution time upper quantile : 1.180711 ms (97.5%)
;;                   Overhead used : 17.111650 ns

accum-defn is faster than accum-defun. Pattern matching does have a tradeoff.

Contributors

Thanks .

License

Copyright © 2023 Dennis Zhuang

Distributed under the Eclipse Public License either version 1.0 or (at

your option) any later version.

More Repositories

1

aviatorscript

A high performance scripting language hosted on the JVM.
Java
3,954
star
2

Metamorphosis

A high available,high performance distributed messaging system.
Java
1,334
star
3

xmemcached

High performance, easy to use multithreaded memcached client in java.
Java
743
star
4

node-zk-browser

A zookeeper web administrator in node.js
JavaScript
336
star
5

gecko

A RPC framework in taobao based on java NIO.
Java
156
star
6

clojure-control

Fabric in clojure
Clojure
136
star
7

ip-service

A demo project for QCon meetup
Clojure
57
star
8

hs4j

HandlerSocket client for java
Java
55
star
9

storm-monitor

A monitor for storm
Clojure
46
star
10

clj.qiniu

Clojure SDK for qiniu. Clojure 七牛云存储 SDK。
Clojure
38
star
11

clj.qrgen

QRCode generator for clojure.
Clojure
34
star
12

erlwsh

Erlang web shell--program erlang on web
Erlang
32
star
13

node-shorten

A url shorten web site in node.js
CSS
28
star
14

clj-xmemcached

Memcached client for clojure.
Clojure
25
star
15

stm-profiler

A profiler for clojure STM
Java
23
star
16

clj-rate-limiter

Rate limiter for clojure that supports a rolling window, either in-memory or backed by redis
Clojure
22
star
17

UniqTask

A task manager for android,just like ES task manager
Java
22
star
18

ring.velocity

Render apache velocity template for ring in clojure.
Clojure
21
star
19

cscheme

Scheme interpreter in clojure
Clojure
16
star
20

cloudcode-test

Cloud code test for avoscloud
JavaScript
15
star
21

carmine-sentinel

A Clojure library designed to connect redis by sentinel, make carmine to support sentinel.
Clojure
14
star
22

clj.monitor

Monitoring applications in clojure based on clojure-control.
Clojure
14
star
23

ik-analyzer

An ik-analyzer github fork,ik-analyzer is a chinese tokenizer used in lucene/solr.
11
star
24

jevent

libevent for java
Java
10
star
25

alfred-workflow

my workflow for alfred
10
star
26

ewok

A high available BTM transaction logs journal using bookkeeper.
Java
9
star
27

clojure-notes

clojure 源码解读
Java
9
star
28

metamorphosis-example

metamorphosis examples
Java
8
star
29

secure-rand

A Clojure library designed to generate secure random float,int,bytes and strings based on java.security.SecureRandom
Clojure
7
star
30

lighthouse

leader election and node register/discover/balance in a service cluster by zookeeper in clojure
Clojure
7
star
31

gen-node-module

the script to generate a node.js module skeleton
JavaScript
6
star
32

UniqRecorder

Android手机的万能记录器,习作
Java
6
star
33

clj.where

A clojure library to query maps in sequence.
Clojure
4
star
34

killme2008.github.com

my github page
JavaScript
4
star
35

prowl

A clojure macro and ruby script to profile clojure program.
Ruby
4
star
36

storm-metamorphosis-spout

A storm spout for metamorphosis
Java
4
star
37

ring-session-memcached

Ring sessions stored in memcached
Clojure
3
star
38

EL-benchmark

EL benchmark for aviator
Java
3
star
39

whetherweather

Weather report and alert for android
Java
3
star
40

fnil.net

My personal web site.
HTML
2
star
41

clojure-overview

首次cn-clojure聚会上介绍的《clojure概览》附带源码
Clojure
2
star
42

coding-practice

Some personal coding pratice
C
2
star
43

erlib

Erlang example code
Erlang
1
star
44

storerl

a simple key-value disk store for erlang
Erlang
1
star
45

ring-jetty-hystrix-adapter

Setup a Hystrix (https://github.com/Netflix/Hystrix) event stream with jetty for clojure.
Clojure
1
star
46

pci4clojure

Programming collective intelligence with clojure
Clojure
1
star
47

learn-node-js

my node.js example code
JavaScript
1
star
48

blog.fnil.net

My Blog Posts
JavaScript
1
star
49

corfu

Paxos in elixir, test project
Elixir
1
star
50

node-properties

A node.js module to read properties config file.
JavaScript
1
star
51

Docker-NodeJS-Ubuntu

Build a docker image that runs node.js application in ubuntu.
Shell
1
star
52

Elixir-OTP-In-Action

《OTP in action》 source code rewrite into elixir.
Elixir
1
star
53

LeanCloud-REST-API-Demo

各种语言调用 LeanCloud REST API 源码示例。
1
star
54

programming-elixir-exercises

My《Programming Elixir》 exercises
Elixir
1
star