chaploud / Sci-Lisp

A Lisp for Scientific Computing written in Rust

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Sci-Lisp

A Lisp for Scientific Computing written in Rust

rust status

Features (WIP)

  • REPL
  • Run as script
  • S-expression
  • Clojure-like syntax (), [], {}, etc...
  • Numpy-like array slice ([2:-1, -3:] array2d)
  • Multiparadigm (Functional, Object-Oriented and Procedural)
  • Supports exception handling
  • Functionality of IPython, numpy, matplotlib, pandas, scipy
  • Digital Signal Processing (DSP) and Time Series Analysis (TSA) included as standard library
  • Well documented
  • Easy installation (Cross Platform)
  • Great developer experience with VSCode extension

Philosophy

Let's use Lisp easily without thinking too hard!

Influenced by

Installation

NOTE: currently most features are not implemented.

Build from source code

Prerequests

Commands

# Clone Repository
git clone https://github.com/chaploud/sci-lisp.git

# build scilisp binary using cargo build
cd sci-lisp
cargo build --release  # => target/release/scilisp
  • You can execute scilisp binary

Get prebuild binary

Windows

Not distributed yet.

Mac

Not distributed yet.

Linux

Not distributed yet.

Command line options

scilisp  # launch REPL
scilisp xxx.slisp  # run as script

Sci-Lisp code examples

See examples/example.slisp.

; Comment

;; ===== Literal
"abc\n"             ; string
#"[0-9]+"           ; regular expression
false               ; false
true                ; true
nil                 ; nil
-999                ; i64
-3.14e15            ; f64
nan                 ; Not a Number
inf                 ; positive infinity
-inf                ; negative infinity
-0.0                ; negative zero
:keyword            ; keyword symbol
'symbol             ; quoted symbol

;; falsy value is only 'false' and 'nil'
;; "", '(), [], {}, #{}, 0, nan => all truthy

;; ===== Collection
; comma is treated as whitespace
'(1, "a", :b)                ; list
[1.0, 2.0, 3.0]              ; vector
{:a "a", :b "b", :c "c"}     ; map (holds the insersion order)
#{:a, :b, :c}                ; set (holds the insersion order)

;; ===== Function Call
(type [1, 2, 3])             ; show type
(time (+ 1 2))               ; measure processing time
(print [1, 2] "abc\n" 123)   ; print any

;; ===== Variable Binding
;; NOTE: Different from Clojure
(def a "abcde")              ; variable (mutable, 'local' scope)
(const C [1, 2, 3])          ; constant value (immutable)

([0|2] a)                    ; slice => "ab"
(-1 C)                       ; back => 3

(let [a 2]                   ; bind variable (local scope)
  (set! a 3)                 ; assign(destructive)
  a)                         ; => 3

;; ===== Function
(defn my-sum [a b]           ; define function
 "sum two value"             ; docstring
  (print a b)
  (+ a b))

(def my-sum                  ; bind function using def
  (fn [a b]                  ; anonymous/lambda function
    (return (+ a b))         ; can use early return
    (- a b)))

(my-sum 1 2)                 ; => 3

;; ===== Control Flow
(if (< 2 3)                  ; if
  true                       ; true form
  false)                     ; false form (must)

(when (< 2 3)                ; when
  (do                        ; true form
    (print "2 < 3")          ; do multiple expressions
    "retval"))

(cond                        ; cond
  (< n 0) "negative"         ; (condition) (expresson)
  (> n 0) "positive"
  :else "default")           ; :else (expression)

(def val "hoge")
(switch val                  ; switch
  ["a"]                      ; match "a"
    (print "A")
  ["b", "c"]                 ; match "b" or "c"
    (print "B or C")
  :default                   ; :default (expression)
    (print "DEFAULT"))

(for [i (range 5)]           ; for loop, range
  (print i))

(def a 0)
(while (< a 10)              ; while loop
  (print a)
  (set! a (+ a 1))
  (if (> a 5)
    (break (+ a 9994))       ; break with return value
    (continue))              ; continue
  (print "never print"))


;; ===== Built-in Functions/Macros

;; Arithmetic
(inc 1)              ; add 1
(dec 1)              ; subtract 1
(+ 1 1)              ; Add
(- 1 1)              ; Subtract
(* 2 3)              ; product
(/ 1 2)              ; devide (float)
(// 1 2)             ; devide
(% 3 2)              ; remainder

;; Compare
(= 2 2 2)            ; equal
(!= 2 3)             ; not equal
(< 2 3)              ; less
(<= 2 3)             ; less equal
(> 2 3)              ; greater
(>= 2 3)             ; greater equal

;; Logical
(and true false)     ; and
(or true false)      ; or
(xor true true)      ; xor
(not false)          ; not

;; Predicates
(nil? nil)
(true? true)
(false? false)
(number? 1)
(i64? 1)
(f64? 1.0)
(zero? 0)
(even? 2)
(odd? 3)
(empty? [])
(string? "abc")
(keyword? :abc)
(symbol? 'abc)
(list? '(1, 2, 3))
(vector? [1, 2, 3])
(map? {:a 1, :b 2})
(set? #{1, 2, 3})

;; Cast
(str 3.14)           ; to string
(str 'abc)
(str :abc)
(i64 "2")              ; to i64
(f64 "2.0")            ; to f64
(list #{1, 2, 3})      ; to list
(vector '(1, 2, 3))    ; to vector
(hmap [:a 1, :b 2])    ; to map
(hset [1, 2, 2])       ; to set

;; Math
(sqrt 2)
(abs -2)             ; absolute value
(cos (* 2.0 *pi*))   ; cosine
(sin (/ *pi* 2))     ; sine
(tan 2.0)            ; tangent
(acos 0.5)           ; arccosine
(asin 0.5)           ; arcsine
(atan 0.5)           ; arctangent
(log 2 10)           ; log_2(10)
(ln *e*)             ; log_e(e), natural logarithm
(log10 2.0)          ; log_10(2.0)
(rand)               ; rondom value 0.0 to 1.0
(randint 0 30)       ; random integer 0 to n

;; Utility
(type [1, 2, 3])              ; show type
(time (+ 1 2))                ; measure processing time
(print {:a 2, :b 3})          ; print any
(doc time)                    ; show docstring
(printf "{0:03}kg" 56)        ; print format (WIP)

;; String
(len "abcde")                 ; length of string
(join [1, 2, 3] ",")          ; join (=> "1,2,3")
(split "1,2,3" "," i64)       ; split (=> [1, 2, 3])
(replace "abc" "a" "x")       ; replace (=> "xbc")
(concat "abc" "def")          ; concat (=> "abcdef")
(trim " abc ")                ; trim (=> "abc")
(in? "a" "12aabc32")          ; is string in string?
(index "abc" "12aabc32")      ; string index in string (=> 3)
(count "abc" "12aabc32")      ; count string in string (=> 1)
(upper-case "abc")            ; upper-case
(lower-case "DEF")            ; lower-case
(lower-camel "abc_def")       ; lowerCamelCase (=> "abcDef")
(upper-camel "abc_def")       ; UpperCamelCase (=> "AbcDef")
(snake-case "abcDef")         ; snake-case (=> "abc_def")
(kebab-case "abcDef")         ; cebab-case (=> "abc-def")
(title-case "abcDef")         ; Title Case (=> "Abc Def")
(train-case "abcDef")         ; Train-Case (=> "Abc-Def")
(shouty-snake "abcDef")       ; SHOUTY_SNAKE_CASE (=> "ABC_DEF")
(shouty-kebab "abcDef")       ; SHOUTY-KEBAB-CASE (=> "ABC-DEF")
(repeat "abc" 2)              ; repeat string (=> "abcabcabc")
(reverse "abc")               ; reverse (=> "cba")
(format "π: {:.2}" 3.1415)    ; format string (WIP)

;; Regular Expression
(find #"[0-9]+" "aa123a")                ; => "123"
(find-all #"No\.(\d+)" "No.1 No.2 No.3") ; => ["hello, world", "world"]
(replace "aa123a" #"[0-9]{2}" "x${1}y")  ; => "aax12y3a"

;; At
(-1 [1, 2, 3])                        ; back => 3

;; Key Access
(:a {:a 1, :b 2, :c 3})               ; get value by key (keyword)
(0 {0 "a", 1 "b", 2 "c"})             ; get value by key (i64)
("a" {"a" 1, "b" 2, "c" 3})           ; get value by key (string)

;; Slice
([0|2] [1, 2, 3])                     ; slice => [1, 2]
([0|-1|2] "abcdefg")                  ; slice with step => "ace"
([|, 1] [[1, 2], [3, 4], [5, 6]])     ; slice => [2, 4, 6]
([|, 1|2] [[1, 2], [3, 4], [5, 6]])   ; slice (like numpy) => [[2], [4], [6]]

;; Vector
(first [1, 2, 3])                     ; first
(last [1, 2, 3])                      ; last
(rest [1, 2, 3])                      ; rest
(len [1, 2, 3])                       ; length of vector
(sum [1, 2, 3])                       ; sum of vector
(mean [1, 2, 3])                      ; mean of vector
(max [1, 2, 3])                       ; max of vector
(min [1, 2, 3])                       ; min of vector
(in? 2 [1, 2, 3])                     ; is element in vector?
(index 2 [1, 2, 3])                   ; index of element
(index-all 2 [1, 2, 3, 2])            ; all index of element
(some? [false, true, false])          ; return true if some truthy
(every? [false, true, false])         ; return true if all truthy
(sort [3, 1, 2] :asc)                 ; sort
(reverse [3, 1, 2])                   ; reverse
(push [3, 1, 2] 4)                    ; push_back
(cons [3, 1, 2] 4)                    ; push_front
(concat [1, 2, 3] [4, 5, 6])          ; concat
(shuffle [3, 1, 2])                   ; shuffle

(def v [1, 2, 3])
(get v 1)                             ; get value by index
(insert! v 1 999)                     ; insert
(remove! v 0)                         ; remove
(replace! v -1 123)                   ; replace

;; Map
(keys {:a 1, :b 2, :c 3})             ; keys
(vals {:a 1, :b 2, :c 3})             ; values
(items {:a 1, :b 2, :c 3})            ; key-value pairs

(def m {:b 2, :c 3})
(get m :b)                            ; get value by key
(insert! m :a 1)                      ; insert/replace
(remove! m :a)                        ; remove
(replace! m :b 123)                   ; replace

;; Set
(def s1 #{2 3})
(get s1 2)                            ; get key
(insert! s 1)                         ; insert/replace
(remove! s 1)                         ; remove
(replace! s 3 123)                    ; replace
(def s2 #{1 2})
(union s1 s2)                         ; union
(intersect s1 s2)                     ; intersect
(difference s1 s2)                    ; difference

;; Functional Programming
(apply + [1, 2, 3])                   ; apply => 6
(map (fn [x] (* x x)) [1, 2, 3])      ; map => [1, 4, 9]
(filter (fn [x] (even? x)) [1, 2, 3]) ; filter => [2]
(reduce + 4 [1, 2, 4])                ; reduce => 11
(-> 1 (+ 2) (/ 6))                    ; thread first => 0.5
(->> 1 (+ 2) (/ 6))                   ; thread last => 2
; ((partial * 10) 1)                  ; partial(WIP) => 10
; ((comp str +) 7 8 9)                ; comp(WIP) => "24"

;; ******************* WIP **********************
;; ===== enum
(enum Grade                       ; define enum
  "Grade Enum"                    ; docstring
  [ECONOMY,
   BUSINESS,
   FIRST])

(def your-grade Grade.FIRST)      ; allow this style

;; ===== struct
(struct Enemy                     ; define struct
  "Enemy Struct"                  ; docstring
  [hp,
   attack])

(def slime
  (Enemy {:attack 2, :hp 20}))    ; using struct
([:attack] slime)                 ; access member => 2
(print slime.attack)              ; allow this style

;; ===== class
(class Animal                     ; define class
  "Animal Class"                  ; docstring

  ;; constructor
  (defn Animal [hp, weight]
    "constructor of Animal"
    (set! self.hp hp)
    (set! self.weight weight))

  ;; member
  (def hp)
  (def weight)
  (defn walk [dist]
    (set! self.hp (- self.hp dist)))
    (format "walk {0}km, HP: {1}",
      dist, self.hp))

(class Dog [Animal]               ; inherit from Animal class
  (defn bow []
    (print "bow!")))

(def dog1 (Dog [100, 200]))       ; instanciate class
(dog1.walk 2)                     ; => "walk 2km, HP: 98"
(dog1.bow)                        ; => nil

;; ===== macro
(macro my-and                     ; define macro
  "Evaluates exprs one at time,
   from left to right."           ; docstring
  ([] true)                       ; multi arity
  ([x] x)
  ([x & next]                ; variable length argument (& rest)
    `(let [and# ~x]          ; quote(`) and unquote(~)
       (if and#                   ; auto-gensym(xxx#)
         (my-and ~@next)          ; unquote splicing(~@)
         and#))))

(my-and "a" "b" "c")              ; => "c"

;; try-catch-finally
;; MultiArity(Autodoc)
;; Polars binding
;; shape
;; Destructuring
;; Parallel
;; SIMD
;; JIT
;; ******************************************

Pronunciation

/sai lisp/

Pull requests are welcome!

  • Currently, execution speed is too slow.
  • You may rewrite it from the design level.

VSCode Extension

Currently only syntax highlight supported.

Futures

About

A Lisp for Scientific Computing written in Rust

License:MIT License


Languages

Language:Rust 99.9%Language:WebAssembly 0.1%Language:Slash 0.0%