0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LIPS Schemeを使ってみました

Posted at

はじめましての投稿になります。
ボケ防止アクティビティの一つとしてプログラミングを勉強している前期高齢者です。
定年退職し、今は妻から家事手伝いと老老介護の指導を受けつつ勉強しています。

背景

ブラウザでLispを手軽に学習できる環境を探していました。
LIPSという処理系サイトを見つけましたのでご紹介したく投稿しました。
「LIPS Scheme v. 1.0.0-beta.20/https://lips.js.org/」
このサイトはLisp方言のSchemeをサポートしています。

早速、簡単なプログラムを試してみました。
[プログラムの実行画面]
lips_test.png

スクリプトの内容

0. 準備

Lisp関数を処理するためには下記が必須です。

<script src="https://cdn.jsdelivr.net/npm/lips@latest/dist/lips.min.js"></script>

1. Lisp関数

JavaScriptのクリックイベント関数から呼ばれるLisp関数です。

<script type="text/x-scheme" bootstrap>
;;二乗処理関数を呼ぶ
(define (doSquareProc)
    (let ((result (squares 1 4)))
        (display result) ;結果表示
        (newline) ;改行出力
        result
    )
)
;;二乗処理関数
(define (squares i end)
    (if (> i end)
        '()
        (let ((x (list i (* i i))))
            (console.log "squares " i (car (cdr x)))
            (append (list x) (squares (+ i 1) end))
        )
    )
)
</script>

2. JavaScript関数

実行ボタンのクリックイベントを受けた時の処理とLispスクリプトの戻り値を画面表示する処理です。

<script type="text/javascript">
// Lipsスクリプト関数(doSquareProc)をコールする
async function excecLips() {
    const [result] = await lips.exec('(doSquareProc)');
    console.log(result);
    const list = putResultInArray(result)
    showResult(list)
}
// Lipsスクリプト関数の戻り値をJS配列に格納する
function putResultInArray(values) {   
    if (values == null || typeof values[Symbol.iterator] !== 'function') {
        return null;
    }
    let rslts = [values.length()];
    let i = 0;
    for (const item of values) {
        console.log(item);
        if(item.car !== undefined && (typeof item.car.valueOf() === 'number')) {
            if(item.cdr !== undefined && (typeof item.cdr.car.valueOf() === 'number')) {
                rslts[i++] = [item.car.valueOf(), item.cdr.car.valueOf()];
                console.log("item.car = ", rslts[i-1][0], "item.cdr.car = ", rslts[i-1][1]);
                i++;
            }
        }
    }
    return rslts;
}
// 結果を画面出力する
function showResult(list) {
    const tbody = document.querySelector('#tbl tbody');
    tbody.innerHTML = '';

    list.forEach(item => {
        const tr = document.createElement('tr');
        tr.innerHTML = `<td>${item[0]}</td><td>${item[1]}</td>`;
        tbody.appendChild(tr);
    })
}
</script>

###3. コード全体

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lipsの関数呼び出しと戻り値取得の確認</title>
    
  </head>

  <body>
    <h2>Lipsお試しサンプル</h2>
    <p><button type="button" onclick="excecLips()">実行</button></p>
    <table id="tbl" border="1">
      <thead><tr><th>&nbsp;&nbsp;i&nbsp;&nbsp;</th><th>&nbsp;i^2&nbsp;</th></tr></thead>
      <tbody></tbody>
    </table>
    <script src="https://cdn.jsdelivr.net/npm/lips@latest/dist/lips.min.js"></script>
    <script type="text/x-scheme" bootstrap>
      (define (doSquareProc)
        (let ((result (squares 1 4)))
          (display result) ;結果表示
          (newline) ;改行出力
          result
        )
      )

      (define (squares i end)
        (if (> i end)
          '()
          (let ((x (list i (* i i))))
            (console.log "squares " i (car (cdr x)))
            (append (list x) (squares (+ i 1) end))
          )
        )
    )
    </script>
    
    <script type="text/javascript">
      //  Lipsスクリプト関数(doSquareProc)をコールする
      async function excecLips() {
        const [result] = await lips.exec('(doSquareProc)');
        console.log(result);
        const list = putResultInArray(result)
        showResult(list)
      }
      // Lipsスクリプト関数の戻り値をJS配列に格納する
      function putResultInArray(values) {   
        if (values == null || typeof values[Symbol.iterator] !== 'function') {
          return null;
        }
        
        let rslts = [values.length()];
        let i = 0;
        for (const item of values) {
          console.log(item);
          if(item.car !== undefined && (typeof item.car.valueOf() === 'number')) {
            if(item.cdr !== undefined && (typeof item.cdr.car.valueOf() === 'number')) {
              rslts[i++] = [item.car.valueOf(), item.cdr.car.valueOf()];
              console.log("item.car = ", rslts[i-1][0], "item.cdr.car = ", rslts[i-1][1]);
              i++;
            }
          }
        }
        return rslts;
      }
      // 結果を画面出力する
      function showResult(list) {
        const tbody = document.querySelector('#tbl tbody');
        tbody.innerHTML = '';

        list.forEach(item => {
          const tr = document.createElement('tr');
          tr.innerHTML = `<td>${item[0]}</td><td>${item[1]}</td>`;
          tbody.appendChild(tr);
        })
      }
    </script>
  </body>
</html>

あとがき

記事を見てくださりありがとうございました。
LipsSchemeもLISPの学習環境としてはよいかと思いました。

Lipsスクリプト関数の戻り値をJS配列に格納する処理ではresultの解析方法が分からずはまりました。
ブラウザのログ出力をみるとcar/cdrらしきデータが見えたのでこんな感じかな的にやってみました。
もっとスマートなやり方があると思います。

また、当初はブラウザがHTMLを読み込んだ時にLipsの実行しようとしてはまりました。
ブラウザ読み込み直後はLips側のロードに時間がかかっているようでJavaScript側の実行と同期がとれずLipsスクリプト関数の呼び出しでUnbound variableエラーになってしましいました。
仕方がなくボタンイベントでスクリプトを実行するようにしました。

LIPSの読み込み完了を待つには lips.ready という Promise が用意されているようです。
暇を見つけて確認しようと思います。忘れなければ...:grin:

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?