The King's Museum

ソフトウェアエンジニアのブログ。

クラウドのもろさとは

昨日起きた AWS の障害。自分の会社も AWS を利用しているので影響を受けた。

この出来事に対してクラウドを利用することへのもろさを懸念する論調が一部であがった。

「もろさ」には二種類あると思う。個別のサービスに対するもろさと、社会全体として見たときのもろさ。

大手が提供するクラウドサービスを利用すること個別のサービスのもろさは低減されると思う。自社でサーバーを管理するよりも高度な体制で管理されているだろうし、今回のような事件があっても復旧は早い。

しかし、多くのサービスが特定の業者のクラウドに依存するようになると、社会としてのもろさは確実に上昇するだろう。オール電化のマンションが停電すると何もできないように。

ウェブサービスが載っかるインターネットは分散システムになっていることとは対照的だと感じた。

あと、このあたりの切り分けをせずにこのことを論じると、なんだか水掛け論だなぁとツイッターなどを見ていて思った。

Scheme の number? と complex?

Scheme にある number?complex? という手続き。

  • number? : 引数が数値であるかどうか
  • complex? : 引数が複素数であるかどうか

(number? x) => #t かつ (complex? x) => #f の数値ってあるのかな?と思った。

リファレンス(6.3.2 数値に関する述語)を見るとまさに解答が書かれていた。

Gaucheでは、数の集合は複素数の集合と同一であり、...(略)

「Gauche では、」ってことは他の処理系ではそういう数値があるのかなぁ?

Dart の非同期プログラミング(Future, async/await)

仕事で Flutter をちょっといじっていて、いい加減 async あたりをちゃんと理解しておこうと思ったのでメモ。

https://dart.dev/tutorials/language/futures

Dart コードはシングルスレッドで実行される

Dart は基本的にシングルスレッドで実行される。 並列処理を行いたい場合は Isolate を利用する。

Future は非同期オペレーションの結果を表す

Future は非同期オペレーションの結果を表している。 ここは Java と同じだね。

Future が完了するまで待つには async 関数で await を使う

void main() async {
  await something();
  print('all done');
}

await を使うためには関数に async を付与する必要がある。

async 関数では以下の条件のいずれかを満たすまで同期的に実行される。 以下のどれかにたどりつくと Future を返し、非同期的に実行される。

  • 関数で最初の await
  • return
  • 関数の終わり

await のあれこれ

await expressionexpression は通常 Future を返す関数である。 しかし、expression が Future を返さない場合は、自動的に Future でラップされる。

なお、await expression 文自体は Future の完了した値を返す。

import "dartd:async";

void main() async {
   // 自動的に Future にラップされ、Future の完了値 int を返す
   int i = await something();
   print(i);
}


int something() {
  return 1;
}

完了を待ちつつスレッドをブロックしない、っていうのが await で気楽に使えるのはいいなぁ。

cut 式とプログラミング Gauche 7章

cut 式

関数を部分適用したい時に使えるらしい。

例えば、

二つのパラメータを取る cons。片方のパラメータを 1 に特殊化したい。

そういう場合には、

(cut cons 1 <>)

と簡潔に書くことができる。

cut 式は実際には lambda の糖衣構文。

(lambda (x) (cons 1 x)) ; = (cut cons 1 <>)

たしかに cut 式の方が簡潔にかける。

ちなみに名前にこれぞという語源はなさそうだ *1

7章: 手続き

7章はちょっと長かったな。以下はメモ。コードはこちら

  • 評価の結果が #<...> のものは読み戻せない
  • 手続きも、数値、文字列、真偽値と同じ、値として他の変数に束縛できる
  • (define (NAME args) expr ...) = (define NAME (lambda (args) expr ...)
    • 前者は MIT 記法
  • for-each: 要素に手続きを適用して、返り値なし
  • map: 要素に手続きを適用して、返り値あり
  • map や for-each は複数のリストを同時に処理できる
  • スコープ
    • let: lambda の糖衣構文。順序は保証されない。
    • let*: let がネストしているだけ。
    • letrec: 初期化式が lambda の場合に変数を参照できる。再帰を書くために使う。
  • ロカール手続きは内部的には letrec として扱われる
  • 可変長引数
    • (define (func a b . c) ...) ⇒ a = 1, b = 2, c = (3 4 5)
    • (define (func . a) ...) ⇒ a = (1 2 3 4 5)
  • apply: リストを unpack して、手続きに適用する
  • match 構文
  • let-optionals* 構文
  • let-keywords 構文
  • cut 構文: 部分適用
    • (cut cons 1 <>) ⇒ (lambda (x) (cons 1 x))
  • 多値
    • リストでも値を返せるが、取り出しが面倒だったり、非効率だったりする
    • receive で受け取る
    • let-values や let*-values でも受け取れる
    • values で返す

プログラミングGauche

プログラミングGauche

プログラミング Gauche:4章〜6章

プログラミング Gauche の4章〜6章のメモ。ちなみにコードはここ

4章: Gauche の開発スタイル

  • Read, Evaluate, Print, Loop => REPL
  • リテラル
    • 数値、真偽値、文字、文字列
    • 1, 3.14, 2/3 => 単一トークン
  • 真偽値
    • #t, #f => #f 以外の値はすべて真
  • 文字
    • #\a, #\あ
  • 文字列
    • "abcd"
  • 読み書き不変性(read/write invariance)
    • REPL の出力はそのまま Gauche に与えることができる
  • 手続き
    • (<手続き> <引数1> <引数2> ...)
    • まずすべての引数が評価される
  • 束縛(bind)
    • (define <変数名> <式>)
    • (define (<手続き名> <引数> ...) <式> ...)
    • 呼び出し => (<手続き名> <引数> ...)
  • 基本の開発スタイル
    • プログラムを書く
    • C-x C-f で読み込み
    • scheme バッファで動作確認
    • プログラムを修正
    • C-x C-e で修正を反映
    • scheme バッファにて動作確認
    • 戻る

5章: プログラムの書式

  • 「スクリプト」、「モジュール」、「パッケージ」
    • スクリプト:実行可能な形式
    • モジュール:再利用可能なライブラリ
    • パッケージ:モジュールやスクリプトを配布可能にしたもの
  • スクリプト
    • 書かれている式を順に評価
    • main という手続きがあればそれを呼び出し
  • コメント
    • ; ⇒ 1行
    • #| |# ⇒ 囲ってる部分
    • #; 後ろのS式が一つ捨てられる
  • 慣習
    • ; ⇒ コードと同じ行に書いて、その行の処理を説明する
    • ;; ⇒ インデントに対してコメントする感じ
    • ;;; ⇒ 大きなコメントブロック
  • 名前と予約語
    • 予約語はない。再定義可能。
  • use
    • use: モジュールの読み込み
    • (use srfi-1) リストモジュール
  • SRFI
    • Scheme Request for Implementation
    • srfi-1 のリストライブラリと srfi-13 の文字列ライブラリをよく使う
    • Gauche ではよく使うものは組み込みでサポートされている

6章:リスト

  • リストのふたつの顔
    • インタプリタは入力されたリストを常に手続きとして解釈
    • データとしてリストを渡したい時はクオートをつける
    • 「クオートが付いていたらデータ。付いていなければプログラムコード」
  • クオート
    • 一度クオートすれば内部もデータになる
  • リストの操作
    • car, cdr, '()
    • (list 1 2 3) ⇒ 1, 2, 3 のリストを作る手続きを実行
    • '(1 2 3) ⇒ 1, 2, 3 のリストというデータを直接与える
    • (cons 1 2) ⇒ (1 . 2) ドット対
    • null?: 引数が空リストかどうか
    • pair?: 引数が空でないリストかどうか
  • クオートと eval
    • eval: データとしてのプログラムとして解釈する
    • (eval '(+ 1 2) (interaction-environment)) ⇒ 3
  • リストの走査
    • fold を使う
    • (<手続き> (... (<手続き> (<手続き> (手続き <初期値>)))...))
    • 繰り返し構文は再帰呼び出しの syntax sugar。
  • 式の前で #?= をいれると式と評価値を出力してくれる
  • cond 式
  • 末尾再帰
  • プログラム自身もリスト

プログラミングGauche

プログラミングGauche

Gauche/Scheme を勉強する(三度目の正直)

過去二回挫折した Gauche/Scheme の勉強を再開したいと思う。

www.thekingsmuseum.info

www.thekingsmuseum.info

今までは少しストイックに勉強しようとしすぎて挫折してしまったきらいがあるので、ゆるく進めていこうと思う。

ついでに、Evernote にまとめたメモも載せていこう。

1章: Lisp と Scheme

  • LISP: 数式処理向けに開発
    • LISt Processing
  • 「リストで表現されたプログラム」を受け取って、それを解釈する
  • S 式
    • 基本要素、もしくは、S式を並べて括弧でくくったもの
      • 1 は数値ひとつの S 式
      • * は記号ひとつ S 式
      • (* 2 3) は記号*、数値2、数値3からなる S 式
  • プログラムとして S 式を次のように解釈
    • (<手続き> <引数> <引数>, …)
    • ⇒ もともとはデータ形式。プログラムとしては M 式があった
  • Scheme はシンプルな言語仕様で組み立てた
    • lambda 式は、「レキシカルな環境を保持した手続き」(クロージャ)へと評価される
    • 手続き呼び出しは継続を伴った引数付き goto である
  • Scheme プログラマは抽象構文木を扱える

2章: Gauche の特徴

  • 手軽にプログラムを書いて試せるスクリプト処理系
  • 実用規模のプログラムまで、機能、性能でスケールする
  • 他の言語のアプリケーションに埋め込み可
  • ネイティブ binding もある

3章: Gauche の設計思想や誕生の背景

  • Perl からの影響
    • 正規表現リテラル
    • 文字列補間
    • モジュールシステム
    • DBI/DBD
  • Common Lisp からの影響
    • キーワード引数
    • オブジェクトシステム
    • コンディション

プログラミングGauche

プログラミングGauche

(c) The King's Museum