Closhure is a dialect of Lisp. It is designed to be an embedded language (minimal Lisp for .NET Framework). It uses Clojure-like syntax.
- Lisp interpreter
- Reflection
- Multi-line input
- Tail call optimization
.NET Framework
Use .sln file.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild /p:Configuration=Release
Usage: Closhure.exe [OPTION] [ARGS...]
Options:
FILE run a script.
-h print this screen.
-r run a REPL.
-v print version.
Operation:
Binds *command-line-args* to a list of strings containing command line args that appear after FILE.
Special forms:
. and catch def defmacro do doseq finally fn if import let loop new or quasiquote quote recur reify set! try
Defined symbols:
* *command-line-args* + - / < <= = == > >= apply eval filter fold gensym instance? list load-file load-string macroexpand map mod nil? not not= nth pr print println prn quot range read read-line read-string slurp spit str symbol type
Macros:
defn dotimes when while
(println "Hello, World!")
, \t
, \r
, \n
, ,
are whitespaces.
; end-of-line comment
' quote
` quasiquote
~ unquote
~@ unquote-splicing
You can use all C#'s data types.
Literals:
> (doseq (x '(3 3L 3.0 3e3 true false nil "string" #"regex" \a :a () [])) (prn x ': (type x)))
3 : System.Int32
3 : System.Int64
3 : System.Double
3000 : System.Double
true : System.Boolean
false : System.Boolean
nil : nil
"string" : System.String
#"regex" : System.Text.RegularExpressions.Regex
\a : System.Char
:a : Closhure.Keyword
() : System.Collections.Generic.List`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
[] : System.Collections.ArrayList
nil
- Characters - preceded by a backslash: \c. \newline, \space, \tab, \formfeed, \backspace, and \return yield the corresponding characters. Unicode characters are represented with \uNNNN as in C#. Octals are represented with \oNNN.
- nil Means 'nothing/no-value'- represents C# null and tests logical false
- Booleans - true and false
> (let [a 1, b 2] (+ a b))
3
> (let (a 1, b 2) (+ a b)) ; , is whitespace. () and [] are interchangeable in special forms.
3
> (doseq [x [1 2 3]] (print x))
123nil
; (try EXPR ... (catch CLASS VAR EXPR ...) ... (finally EXPR ...))
> (try (quot 1 0) (catch System.DivideByZeroException e 'c) (finally (println 'f)))
f
c
In a function, lexical scoping is used.
Functions implement IComparer interface.
Callable
> (. * call)
1
IComparer
> (def a (list 3 2 1))
(3 2 1)
> (. a Sort -)
nil
> a
(1 2 3)
> ((fn [x y] (+ x y)) 1 2)
3
> ((fn [x] (* x 2)) 3)
6
> (defn foo [x & more] (list x more)) ; variadic function
(fn [x & more] (list x more))
> (foo 1 2 3 4 5)
(1 (2 3 4 5))
> (defn sum [x y] (+ x y))
(fn [x y] (+ x y))
> (sum 1 2)
3
> (fold + '(1 2 3))
6
> (defn even? [x] (== 0 (mod x 2)))
(fn [x] (== 0 (mod x 2)))
> (even? 3)
false
> (even? 4)
true
> (apply + (list 1 2 3))
6
> (map (fn [x] (. System.Math Sqrt x)) (list 1 2 3 4))
(1 1.4142135623731 1.73205080756888 2)
> (filter even? (list 1 2 3 4 5))
(2 4)
> (= "abc" "abc") ; Object.equals()
true
> (def x 1)
((fn [x] (println x) (set! x 3) (println x)) 4) ; lexical scoping
x
4
3
1
> (defn adder [amount] (fn (x) (+ x amount))) ; lexical scoping
(def add3 (adder 3))
(add3 4)
7
> (symbol "a")
a
> 'a| symbol with special characters|
a symbol with special characters
apply, doseq, filter, fold, map work on System.Collections.IEnumerable.
> (apply + (filter (fn [x] (or (== 0 (mod x 3)) (== 0 (mod x 5)))) (range 1 1000)))
233168
Evaluates the arguments in order. Execution then jumps back to the recursion point, a loop or fn method.
Warning: recur
does not check the tail position.
> (defn sum1 [n s] (if (< n 1) s (recur (- n 1) (+ s n))))
> (defn sum [n] (sum1 n 0))
> (defn sum-nonrecur [n] (if (< n 1) 0 (+ n (sum-nonrecur (- n 1)))))
> (sum 100)
5050
> (sum-nonrecur 100)
5050
> (sum 1000)
500500
> (sum-nonrecur 10000)
Process is terminated due to StackOverflowException.
> (loop [i 0] (when (< i 5) (print i) (recur (+ i 1))))
01234nil
doseq
, fn
, let
, loop
make new scope.
> (. (list 2 4 6) get_Item 1)
4
> ((list 2 4 6) 1) ; implicit indexing
4
> (. [1 2 3] -Count)
3
Macro is non-hygienic.
> (defmacro infix (a op & more) `(~op ~a ~@more))
nil
> (infix 3 + 4)
7
> (infix 3 + 4 5)
12
> (macroexpand '(infix 3 + 4 5))
(+ 3 4 5)
> (macroexpand '(while true (println 1)))
(loop () (if true (do (println 1) (recur))))
> (import System) ; System is imported by default.
nil
> (import System.Math) ; Clojure syntax
System.Math
> [(. (Random.) NextDouble) (.NextDouble (new Random))]
(0.207981260590247 0.207981260590247)
> (. Math Floor 1.5) ; class's static method.
1.0
> (. "abc" -Length) ; object's property
3
> (. "abc" get_Length) ; also object's property (C#'s feature)
3
> (. true ToString)
"True"
> [(. System.Math -PI) System.Math/PI]
(3.14159265358979 3.14159265358979)
> (. Closhure.Core -testField)
nil
> (set! (. Closhure.Core -testField) 1) ; set field
(. Closhure.Core -testField)
1
> (set! Closhure.Core/testField "abc")
Closhure.Core/testField
"abc"
> (set! (. Closhure.Core -testProperty) 3)
3
> [Closhure.Core/testProperty (. Closhure.Core -testProperty)]
(3 3)
> (. Closhure.Core set_testProperty 4) ; (C#'s feature) method-like: prepend set_ to property name to set
nil
> (. Closhure.Core get_testProperty) ; (C#'s feature) method-like: prepend get_ to property name to get
4
> (str (reify Object (ToString [this] (str "reified object: " this))))
"reified object: System.Object"
> (def h (new System.Collections.Hashtable))
System.Collections.Hashtable
> (. h Add "a" "apple")
nil
> [(. h -Item 0) (. h -Item "a")]
(nil "apple")
> (new |System.Collections.Generic.List`1[System.Int32]|)
()
Specifying types · clojure/clojure-clr Wiki
See the source code for details.