LoginSignup
17

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-12-05

ども、@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))

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17