ども、@nobkzです
Lisp Flavored Erlangについて
LFEとは?
Erlang VM上で動くLispです!
今回は基本的な、データ型を、構文を紹介するだけです。これも記事を分けて書いていきます。
基本的なLFEのデータ型やら基礎
アトム
LFEはquoteして、アトムを作ります。
>> 'atom
atom
数値型
数値はこんな感じ
>> (+ 1 2 3 4)
10
>> (- 1 2 3 4)
-8
>> (* 1 2 3 4)
24
>> (/ 10 2 2 2)
1.25
ブール型
真偽値もquoteしてください
>> (and 'true 'false)
false
等値演算について
>> (=:= 5 5)
true
>> (=:= 1 0)
false
>> (=/= 1 1)
false
>> (=:= 5 5.0)
false
>> (== 5 5.0)
true
>> (/= 5 5.0)
false
大小は
>> (< 1 0)
false
>> (> 1 0)
true
>> (>= 0 1)
false
>> (=< 0 1)
true
リスト
リストはLispいつもの通り
>> '(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の文字列が数字のリストとして表現されているのも、ちゃんとですね...
>> '(98 99 100)
"bcd"
>> (++ '(98 99 100) '(101))
"bcde"
>> (car "hello")
104
>> (cdr "hello")
"ello"
タプル
まぁ、ありますよね。
>> (tuple 'ok 'false 1 "sample")
#(ok false 1 "sample")
>> #(tuple (+ 1 1))
#(tuple (+ 1 1))
>> (tuple (+ 1 1))
#(2)
ビット構文
>> (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とします
(defmodule first_module
(export (hello 0) (add 2)))
(defun hello ()
(io:fomat "hello world!"))
(defun add (x y)
(+ x y))
replではこうします。
>> (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
(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
(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))