string-reverse

SRFI-13 に string-reverse という手続きがある。その名のとおり、文字列を逆順にする手続きだ。

gosh> (use srfi-13)
#<undef>
gosh> (string-reverse "abcdefg")
"gfedcba"

で、何故か省略可能な引数が2つあって、逆順にするときの始端と終端を指定できる(逆順になった部分文字列が返ってくる)。

gosh> (string-reverse "abcdefg" 3)
"gfed"
gosh> (string-reverse "abcdefg" 3 5)
"ed"

これを自分で作ってみた。こないだの case-lambda の練習。

(define string-reverse
  (case-lambda
    ((s) (string-reverse s 0 (string-length s)))
    ((s start) (string-reverse s start (string-length s)))
    ((s start end)
      (let loop ((c 0) (l (string->list s)) (r '()))
        (cond ((= c end) (list->string r))
              ((< c start) (loop (+ c 1) (cdr l) r))
              (else (loop (+ c 1) (cdr l) (cons (car l) r))))))))

(print (string-reverse "abcdefg"))
(print (string-reverse "abcdefg" 3))
(print (string-reverse "abcdefg" 3 5))
takatoh@apostrophe $ gosh string-reverse.scm
gfedcba
gfed
ed

リストから要素を間引きする

真ん中優先。真ん中がないときは右側優先。

(define thin-out
  (lambda (lis n)
    (let* ((r (- (length lis) n))
      (a (if (= (mod r 2) 0) (/ r 2) (+ (div r 2) 1)))
      (b (+ a n)))
      (append (take lis a) (drop lis b)))))

(print (iota 10))
(print (thin-out (iota 10) 1))
(print (thin-out (iota 10) 2))
(print (thin-out (iota 10) 3))
^o^ > gosh thin-out.scm
(0 1 2 3 4 5 6 7 8 9)
(0 1 2 3 4 6 7 8 9)
(0 1 2 3 6 7 8 9)
(0 1 2 3 7 8 9)

リストのn番目の要素を削除する

最初の要素は0番目。

(define delete-nth
  (lambda (lis n)
    (let loop ((c 0) (l lis) (r '()))
      (if (null? l)
          (reverse r)
          (if (= c n)
            (loop (+ c 1) (cdr l) r)
            (loop (+ c 1) (cdr l) (cons (car l) r)))))))

(print (iota 10))
(print (delete-nth (iota 10) 3))
(print '(a b c d e f g h i j))
(print (delete-nth '(a b c d e f g h i j) 3))
^o^ > gosh delete-nth.scm
(0 1 2 3 4 5 6 7 8 9)
(0 1 2 4 5 6 7 8 9)
(a b c d e f g h i j)
(a b c e f g h i j)

ちゃんと 3 と d が消えている。

これを拡張して、「n番目」を複数とれるようにしてみよう。

(define delete-nth
  (lambda (lis . ns)
    (let loop ((c 0) (l lis) (r '()))
      (if (null? l)
          (reverse r)
          (if (include? c ns)
              (loop (+ c 1) (cdr l) r)
              (loop (+ c 1) (cdr l) (cons (car l) r)))))))

(define include?
  (lambda (x lis)
  (cond ((null? lis) #f)
        ((= x (car lis)) #t)
        (else (include? x (cdr lis))))))

(print (iota 10))
(print (delete-nth (iota 10) 3 5 7))
(print '(a b c d e f g h i j))
(print (delete-nth '(a b c d e f g h i j) 3 5 7))
^o^ > gosh delete-nth2.scm
(0 1 2 3 4 5 6 7 8 9)
(0 1 2 4 6 8 9)
(a b c d e f g h i j)
(a b c e g i j)

要素がリストに含まれているか否かを判定する述語が見当たらなかったので、include? を自作した。

整数のリストを作る(2)-あるいは省略可能な引数の扱いについて

先週のエントリを見て省略可能な引数を扱う方法を書いてくれた人がいる。

 cf. 省略可能引数 – 主題のない日記

そこでは、R6RS/R7RS で定められている case-lambda と Gauche の拡張である let-optionals* が紹介されている。どちらも省略可能な引数を簡単に扱うためのマクロのようだ。

my-iotacase-lambda を使って書くとこうなる。

(define my-iota
  (case-lambda
    ((count) (my-iota count 0 1))
    ((count start) (my-iota count start 1))
    ((count start step)
      (let loop ((c count)
        (i (+ start (* (- count 1) step)))
        (lis '()))
        (if (= c 0)
            lis
            (loop (- c 1) (- i step) (cons i lis)))))))

(print (my-iota 10))
(print (my-iota 10 2))
(print (my-iota 10 2 2))
(print (my-iota 10 2 -2))

ついでに step に負数を指定すると期待通りに動作しない不具合も直しておいた。
実行例:

^o^ > gosh my-iota4a.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)
(2 0 -2 -4 -6 -8 -10 -12 -14 -16)

一方、let-optionals* を使って書くとこんな感じ:

(define my-iota
  (lambda (count . restargs)
    (let-optionals* restargs
      ((start 0)
       (step 1))
      (let loop ((c count)
        (i (+ start (* (- count 1) step)))
        (lis '()))
        (if (= c 0)
            lis
            (loop (- c 1) (- i step) (cons i lis)))))))

(print (my-iota 10))
(print (my-iota 10 2))
(print (my-iota 10 2 2))
(print (my-iota 10 2 -2))
^o^ > gosh my-iota4b.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)
(2 0 -2 -4 -6 -8 -10 -12 -14 -16)

当然ながら実行結果はどちらも同じだけど、どちらかというと case-lambda のほうが好みだな。引数の数でパターンマッチしてる感じがいい。let-optionals* だと省略可能引数の部分だけ別に書くことになるのでコードの見通しが悪いような気がする。

Gauche のマニュアルだと、case-lambdahttp://practical-scheme.net/gauche/man/gauche-refj_24.html の一番下、let-optionals*http://practical-scheme.net/gauche/man/gauche-refj_58.html6.18.4 省略可能引数のパージング にある。

整数のリストを作る

たまには Scheme を。

Scheme で整数のリストを作るには iota 手続きが使える。

^o^ > gosh
gosh> (iota 10)
(0 1 2 3 4 5 6 7 8 9)
gosh> (iota 10 2)
(2 3 4 5 6 7 8 9 10 11)
gosh> (iota 10 2 2)
(2 4 6 8 10 12 14 16 18 20)

これを自前で実装してみよう。
最初に作ったのがこれ。可変長引数なので、引数の数に応じて対応する補助手続きを呼び出している。

(define my-iota
  (lambda (n . args)
    (cond ((null? args) (my-iota-simple n))
          ((= (length args) 1) (my-iota-start n (car args)))
          (else (my-iota-step n (car args) (cadr args))))))

(define my-iota-simple
  (lambda (n)
    (let loop ((start 0) (i (- n 1)) (lis '()))
      (if (< i start)
          lis
          (loop start (- i 1) (cons i lis))))))

(define my-iota-start
  (lambda (n start)
    (let loop ((i (- (+ start n) 1)) (lis '()))
      (if (< i start)
          lis
          (loop (- i 1) (cons i lis))))))

(define my-iota-step
  (lambda (n start step)
    (let loop ((i (+ start (* (- n 1) step))) (lis '()))
      (if (< i start)
          lis
          (loop (- i step) (cons i lis)))))) (print (my-iota 10))

(print (my-iota 10 2))
(print (my-iota 10 2 2))

実行例:

^o^ > gosh my-iota.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)

上の実装では3つの補助手続きを定義しているけど、内容は同じようなものなので1つにまとめることにした。つまり、引数を3つとる補助手続き my-iota-general を定義しておいて、本体手続き my-iota のほうで場合分けをして呼び出す。

(define my-iota
  (lambda (n . args)
    (cond ((null? args) (my-iota-general n 0 1))
          ((= (length args) 1) (my-iota-general n (car args) 1))
          (else (my-iota-general n (car args) (cadr args))))))

(define my-iota-general
  (lambda (n start step)
    (let loop ((i (+ start (* (- n 1) step))) (lis '()))
      (if (< i start)
          lis
          (loop (- i step) (cons i lis))))))

(print (my-iota 10))
(print (my-iota 10 2))
(print (my-iota 10 2 2)) 
^o^ > gosh my-iota2.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)

だいぶシンプルになった。もう一歩進めてみよう。上の my-iota 手続きの中では場合分けをして my-iota-general の引数 start、step を決めているので、let で局所変数にしてしまえば my-iota-general の本体部分を取り込むことができる。

(define my-iota
  (lambda (n . args)
    (let ((start (if (>= (length args) 1) (car args) 0))
          (step (if (>= (length args) 2) (cadr args) 1)))
         (let loop ((i (+ start (* (- n 1) step))) (lis '()))
           (if (< i start)
               lis
               (loop (- i step) (cons i lis)))))))

(print (my-iota 10))
(print (my-iota 10 2))
(print (my-iota 10 2 2)) 
^o^ > gosh my-iota3.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)

めでたく1つの手続きにできた。

逆関数法で指数分布する乱数を生成する

[0,1)区間の一様乱数から、指数分布にならう乱数を生成するには、逆関数法というのが使える。
指数分布の密度関数は、パラメータをτとすると:
$$ f(\tau)=\lambda e^{-\lambda\tau} $$
であり、分布関数 g(τ) は:
$$ g(\tau)=\int^\tau_{-\infty}{\lambda e^{-\lambda\tau}}d\tau=1-e^{-\lambda\tau} $$
となる。g(τ)は 0~1 の値をとるので、この逆関数:
$$ \tau=-\frac{1}{\lambda}log(1-g(\tau)) $$
の g(τ) の代わりに一様乱数を入力してやれば、τ は指数分布する乱数になる。

じゃあ Ruby でやってみよう。

# encoding: Windows-31J

class RandExpon
  def initialize(lamda)
    @lamda = lamda
    @r = Random.new
  end

  def rand
    -1.0 / @lamda * Math.log(1 - @r.rand)
  end
end

expon = RandExpon.new(0.5)
  10000.times do |i|
  puts expon.rand
end
expon

λ=0.5とし、10000個の乱数を発生させている。
これを Excel でグラフ化したのがこれ。

「指数分布」の曲線は、上に書いた密度関数の曲線を、スケールを合わせるために8000倍して描いている。乱数はちゃんと指数分布になっているようだ。

参考にしたページ:
 cf. http://www.ishikawa-lab.com/montecarlo/4shou.html

Box-Muller法で正規分布する乱数を生成する

一様分布する乱数から、正規分布に従う乱数を生成する方法に、Box-Muller法というのがある。
Wikipediaによれば、(0,1) 区間の一様分布乱数2つ(X,Y)から、下の式で2つの正規分布乱数 $ Z_1 $ と $ Z_2 $ が得られる。

$$
Z_1=\sqrt{-2log{X}}\cos{2\pi{Y}}
Z_2=\sqrt{-2log{X}}\sin{2\pi{Y}}
$$

$ Z_1 $ と $ Z_2 $ は標準正規分布となるので、これらに標準偏差 σ をかけて平均 μ を足してやれば、任意の正規分布に従う乱数が得られる。

Ruby で 10000個の乱数を発生させるスクリプトを書いてみた。ここでは平均 μ=1.0、標準偏差 σ=0.2 とした。

# encoding: Windows-31J

class BoxMuller
  def initialize(mu, sigma)
    @mu = mu
    @sigma = sigma
    @r = Random.new
    @z2 = nil
  end

  def rand
    if @z2
      z1 = @z2
      @z2 = nil
    else
      x = @r.rand
      y = @r.rand
      z1 = Math.sqrt(-2.0 * Math.log(x)) * Math.sin(2 * Math::PI * y)
      @z2 = Math.sqrt(-2.0 * Math.log(x)) * Math.cos(2 * Math::PI * y)
    end
    @sigma * z1 + @mu
  end
end

bm = BoxMuller.new(1.0, 0.2)
10000.times do |i|
  puts bm.rand
end

結果を Excel でグラフ化してみた。水色の点が 0.1 単位のヒストグラム。黄緑の線が Excel に用意されている NORM.DIST 関数で描いたもの(スケールを合わせるために NORM.DIST 関数の値は 1000 倍している)。

Box-Muller

こうしてみると、ほぼぴったりと正規分布になっているようだ。

ちなみに Excel で平均値と標準偏差を求めたら、それぞれ μ=0.997、σ=0.201 となった。

Windowsマシンで動かしているSinatraアプリにほかのマシンからアクセスできなくてハマった

おおよその事情はタイトルの通り。
Windows マシンで Sinatra アプリを動かす。

^o^ > rackup config.ru

ポート 9292 で待機するので、ほかのマシンからアクセスするも繋がらない。ローカルホストからだとちゃんと繋がるので、アプリのせいではない……と思ったら、これが大間違いだった。

最初、ファイアウォールのせいだと思って Norton Internet Security のポート開放方法とかをググって試してみたけど、どうやっても繋がらない。
さんざんやったあげく、ふと Sinatra で同じ目にあってる人がいるかと思って「ruby sinatra ポート」でググったら、次のページを見つけた。

 cf. Sinatraがデフォルトでは外部から繋がらなくなってたよ – Qiita

なんてこった。Sinatra 1.4.0 から development 環境ではデフォルトでローカルホストからしかアクセスを受け付けなくなったようだ。
ともあれ、原因と解決法が分かった。次のようしてどのホストからのアクセスも受け付けるようにすればいい。

^o^ > rackup -o 0.0.0.0 config.ru

これで無事OK。

新しいPCが届いたのでWindowsを消してUbuntuをインストールした

今日一日かけて作業した。Ubuntu 16.04 LTS。ホスト名は muffinman。
宅内ネットワークの Webサーバ用。apostrophe(旧nightschool)で動かしていた Sinatra アプリ2つを移設。いくつかハマりどころがあったけど、なんとか終わった。
ホントはちゃんと作業記録を残しておくべきなんだろうけど、覚えていないので書けない。まあ、うまくいったからいいか。