info

Lisp(scheme)のどこがうれしいの?

言語オタで無い人向けに説明するための、自分の中でのまとめ

1.関数がファーストクラスオブジェクトでなにがうれしいの?
高階関数で、小さい問題のためにわざわざクラスを作るほどコードが肥大化しない。少し挙動が違うハンドラとかコールバックとか作っていろいろな所に持ち回りたい時使える、下のコードで言うと関数オブジェクトを持っていけばどこでもロケットが発射できる

ちょっと違う挙動をする関数をクラスを使わず作れることを、C言語に似た文法の疑似コードで表わしてみる。
gccコンパイルできるけどsegvで落ちるよ。いつかクラスベースの記述で比較コードを書く、いつか

/*ロケットをカウントダウンして発射するプログラム、make_rocketに与えられた引数は発射までのカウント数を表わす。make_rocketは与えられたカウント数のrocket関数を返し呼ばれるたびカウントダウンされる。*/
#include <stdio.h>
typedef void (*func)(void);

func make_rocket(int i)
{
  void rocket()
  {
    if (i < 0)
      {
        printf("ロケットは発射されました\n");
      }
    else if (i == 0)
      {
        printf("発射!\n");
      }
    else
      {
        printf("%d!\n", i);
      }
    i--;
  }

  return rocket;
}

int main()
{
  func one = make_rocket(5);
  func two = make_rocket(5);
  func tree = make_rocket(5);
  int i;

  for(i = 0; i < 5; i++)
    {
      one();
      two();
      tree();
    }
  return 0;
}

scheme(gauche)実際に動くコードに翻訳

(define (make-rocket n rocno)
  (lambda ()
      (set! n (- n 1))
      (cond ((< n 0) #`",|rocno|番ロケットは既に発射されました\n")
            ((= n 0) #`",|rocno|番ロケット発射!\n")
            (else #`"No.,|rocno| ,|n|!\n"))))

(define (main args)
  (let ((one (make-rocket 3 1)) (two (make-rocket 7 2)) (tree (make-rocket 5 3)))
    (let loop ((i 7))
      (when (not (= i 0))
        (print (one) (two) (tree)) (loop (- i 1))))))

実行結果

No.1 2!
No.2 6!
No.3 4!

No.1 1!
No.2 5!
No.3 3!

1番ロケット発射!
No.2 4!
No.3 2!

1番ロケットは既に発射されました
No.2 3!
No.3 1!

1番ロケットは既に発射されました
No.2 2!
3番ロケット発射!

1番ロケットは既に発射されました
No.2 1!
3番ロケットは既に発射されました

1番ロケットは既に発射されました
2番ロケット発射!
3番ロケットは既に発射されました

2.S式が構文で何がうれしいの?
S式はデータファイルでもある(XMLとかJSONみたいな)それの読み込みを「標準で」備えてる
木構造手書きできるから自分の好きなように構文をいじれて、宗教戦争にならない