(lisp (flavored (erlang)))について基本その1

ども、@nobkzです

# Lisp Flavored Erlangについて

## LFEとは?

Erlang VM上で動くLispです!


今回は基本的な、データ型を、構文を紹介するだけです。これも記事を分けて書いていきます。



## 基本的なLFEのデータ型やら基礎

### アトム

LFEはquoteして、アトムを作ります。

```cl
>> 'atom
atom
``` 
### 数値型

数値はこんな感じ

```cl
>> (+ 1 2 3 4)
10
>> (- 1 2 3 4)
-8
>> (* 1 2 3 4)
24
>> (/ 10 2 2 2)
1.25
```



### ブール型

真偽値もquoteしてください

```cl
>> (and 'true 'false)
false
```

等値演算について

```cl
>> (=:= 5 5)
true
>> (=:= 1 0)
false
>> (=/= 1 1)
false
>> (=:= 5 5.0)
false
>> (== 5 5.0)
true
>> (/= 5 5.0)
false
```

大小は

```cl
>> (< 1 0)
false
>> (> 1 0)
true
>> (>= 0 1)
false
>> (=< 0 1)
true
```

### リスト

リストはLispいつもの通り

```cl
>> '(a b c d)
(a b c d)
>> (cons 'a (cons 'b (cons 'c (cons 'd ()))))
(a b c d)
>> (cons 'a 'b)
(a . b)
>> (car '(a b c))
a
>> (cdr '(a b c d))
(b c d)
```

えっと、Erlangの文字列が数字のリストとして表現されているのも、ちゃんとですね...

```cl
>> '(98 99 100)
"bcd"
>> (++ '(98 99 100) '(101))
"bcde"
>> (car "hello")
104
>> (cdr "hello")
"ello"
```

### タプル

まぁ、ありますよね。

```cl 
>> (tuple 'ok 'false 1 "sample")
#(ok false 1 "sample")
>> #(tuple (+ 1 1))
#(tuple (+ 1 1))
>> (tuple (+ 1 1))
#(2)
```

### ビット構文


```cl 
>> (binary "I am nobkz. I am a lisp Programmer")
#B(73 32 97 109 32 110 111 98 107 122 46 32 73 32 97 109 32 97 32 108 105 115 112 32 80 114 111 103 114 97 ...)
> (binary (10 (size 8)) (242 (size 8)) (102 (size 8)))
#B(10 242 102)
```

## モジュール、関数

モジュールを作るにはこうします。

ファイル名が。first_module.lfeとします

```cl
(defmodule first_module
  (export (hello 0) (add 2)))


(defun hello ()
  (io:fomat "hello world!"))

(defun add (x y)
  (+ x y))

```

replではこうします。

```cl 
>> (c "first_module.lfe")
#(module first_module)
>> (first_module:hello)
hello world!ok
>> (first_module:add  1 2)
3
```


# 今日はここまで

次回は、パターンマッチ、とErlangのデータ型や、Erlangのライブラリ呼び出しをやります。あと、マルチプロセス基本構文もやります。

# Erlang本をLFEで写経したコード


## テキトーにこんな感じになります!

すごいE本の、サンプルをLFEに書き直したらこうなります

13章の、evserv.lfe

```cl
(defmodule evserv
  (export all))

(defrecord state events clients)
(defrecord event
  (name "")
  (description "")
  pid
  (timeout (tuple (tuple 1970 1 1) (tuple 0 0 0))))

(defun init ()
  (loop (make-state events (orddict:new)
                    clients (orddict:new))))



(defun loop (state)
  (case state
    [(match-state events events clients clients)
     (receive
       [(tuple pid msg-ref (tuple 'subscribe client))
        (let* ([ref (erlang:monitor 'process client)]
               [new-clients (orddict:store ref client clients)])
          (! pid (tuple msg-ref 'ok))
          (loop (set-state-clients state new-clients)))]
       [(tuple pid msg-ref (tuple 'add name description timeout))
        (if (valid-datetime timeout)
          (let* ([event-pid (event:start_link name timeout)]
                 [new-events (orddict:store name
                                            (make-event name name
                                                        description description
                                                        pid event-pid
                                                        timeout timeout)
                                            events)])
            (! pid (tuple msg-ref 'ok))
            (loop (set-state-events state new-events)))
         (progn (! pid (tuple msg-ref (tuple 'error 'bad_timeout)))
                (loop state)))]
       [(tuple pid msg-ref (tuple cancel name))
        (let ([events (case (orddict:find name events)
                        [(tuple 'ok e) (event:cancel (event-pid e))]
                        ['error events])])
          (! pid (tuple msg-ref 'ok))
          (loop (set-state-events state events)))]
       [(tuple 'done name)
        (case (orddict:find name events)
          [(tuple 'ok e)
           (send-to-clients (tuple 'done (event-name e) (event-description e)) clients)
           (loop (set-state-events state (orddict:erase name events)))]
          ['error (loop state)])]
       ['shutdown (exit 'shutdown)]
       [(tuple 'DOWN ref 'process _pid _reason) (loop (set-state-clients state (orddict:erace ref clients)))]
 ;;   ['code_change (: (MODULE) loop state)]
       [unkown (io:format "Unkown message: ~p~n" `(,unkown)) (loop state)]
       )]))

(defun valid-datetime
  ([(tuple date time)]
  (try (andalso (calendar:valid_date date) (valid-time time))
       (catch
         [error:function_clause 'false])))
  ([(other)] 'false))

(defun valid-time
  ([(tuple h m s)]
   (when (>= h 0) (< h 24)
         (>= m 0) (< m 60)
         (>= s 0) (< s 60))
   'true)
  ([_] 'false))

(defun send-to-clients (msg clientdict)
  (orddict:map (lambda (_ref, pid) (! pid msg)) clientdict))

(defun start ()
  (let ([pid (spawn (MODULE) 'init ())])
    (register (MODULE) pid)
    pid))

(defun start_link ()
  (let ([pid (spawn_link (MODULE) 'init ())])
    (register (MODULE) pid)
    pid))

(defun terminate ()
  (! (MODULE) 'shutdown))

(defun subscribe (pid)
  (let ([ref (erlang:monitor 'process (whereis (MODULE)))])
    (! (MODULE) (tuple (self) ref (tuple 'subscribe pid)))
    (receive
      [(tuple ref 'ok) (tuple ref 'ok)]
      [(tuple 'DOWN 'process _pid reason) (tuple 'error reason)]
      [after 5000 (tuple 'error 'timeout)])))

(defun add-event (name description timeout)
  (let ([ref (make_ref)])
    (! (MODULE) (tuple (self) ref (tuple 'add name description timeout)))
    (receive
      [(tuple ref msg) msg]
      [after 5000 (tuple 'error 'timeout)])))

(defun cancel (name)
  (let ([ref (make_ref)])
    (! (MODULE) (tuple (self) ref (tuple 'cancel name)))
    (receive
      [(tuple ref 'ok) 'ok]
      [after 5000 (tuple 'error 'timeout)])))

(defun listen (delay)
  (receive
    [(tuple 'done name description) (cons (tuple 'done name description) (listen 0))]
    [after (* delay 5000) ()]))

```


14章の、kity_gen_server.lfe

```cl
(defmodule kitty_gen_server
  (export all)
  (behavior 'gen_server))

(defrecord cat
  name
  (color 'green)
  description)

(defun start_link ()
  (gen_server:start_link (MODULE) () ()))

(defun order_cat (pid name color description)
  (gen_server:call pid (tuple 'order name color description)))

(defun return_cat (pid cat)
  (gen_server:cast pid (tuple 'return cat)))

(defun close_shop (pid)
  (gen_server:call pid 'terminate))

(defun init
  [(()) (tuple 'ok ())])

(defun handle_call
  [((tuple 'order name color description) _from cats)
   (if (== cats ())
     (tuple 'reply (make_cat name color description) cats)
     (tuple 'reply (hd cats) (tl cats)))]
  [('terminate _from cats) (tuple 'stop 'normal 'ok cats)])

(defun handle_cast
  [((tuple 'return cat) cats) (tuple 'noreply (cons cat cats))])


(defun handle_info (msg cats)
  (io:format "Unexpected message: ~p~n" `(,msg))
  (tuple 'noreply cats))

(defun terminate (normal cats)
  (lists:map (lambda (c) (io:format "~p was set free.~n" `(,(cat-name c))))
             cats)
  'ok)

(defun code_change (_oldvsn state _extra)
  (tuple 'ok state))

(defun make_cat (name col desc)
  (make-cat name name color col description desc))

```