トップ «前の日記(2007-05-20) 最新 次の日記(2007-05-23)» 編集

Route 477



2007-05-21

[scheme] unfoldの使い方がわからない

from http://d.hatena.ne.jp/rui314/20070521/p1

なんかfoldの逆を行う関数(unfold)があるらしい。

  • fold → リストを順番に畳みこんで値にする
  • unfold → 値を順番に並べてリストにする

google code searchにこんなコードが

(define (fontset->list-of-patterns fs)
  (let ((count (xft-fontset-count fs)))
    (unfold
     (lambda (x)
       (equal? count x))
     (lambda (index)
       (xft-pattern-duplicate
	(xft-fontset-ref fs index)))
     (lambda (x)
       (+ x 1))
     0)))

なんか、do の代わりに使えそうな感じか?

iotaでも作ってみるかな。

(use srfi-1)

(define (my-iota to from)
  (unfold
    (lambda (i) (> i to)) ;終了条件
    identity              ;種から値を作る
    (lambda (i) (+ i 1))  ;種から次の種を作る
    from))                ;最初の種

(display (my-iota 10 1))
yhara@meteor:~/HTML/gauref % gosh sample-unfold.scm
(1 2 3 4 5 6 7 8 9 10)

わーい iota できたよー。

[scheme] unfoldでstring-tailsを作ってみた

例えば "hoge" という文字列から ("hoge" "oge" "ge" "e") というリストを作りたいとしよう。

これはunfoldを用いて以下のように書ける。

(define (string-tails str) 
  (unfold (cut = (string-length str) <>)
          (cut string-drop str <>) 
          (cut + 1 <>) 
          0))

(なんとなくlambdaの代わりにcutを使いまくってみました)

試してみよう。

gosh> (string-tails "hoge")
("hoge" "oge" "ge" "e")

うまく動いている模様。

しかし「それiotaとmapでできるよ」と言われそうな予感も。

(define (string-tails str) 
  (map (cut string-drop str <>) 
       (iota (string-length str)))) 

うーん、こっちの方が短いし分かりやすい気がしてきた^^;

余談1 : リストのtails

Haskellだとimport Listしてtailsで一発である。Schemeでもリストのtailsは下のように簡単に書けるのだが、 Schemeでは文字列はリストではないのでこれを文字列に適用することはできない。

(use srfi-1)
(define (tails ls) (pair-fold cons '() ls)) ;pair-foldはcdrに対してfoldするやつ

余談2 : 部分適用

あと (+) 1 の方が (cut + 1 <>) より格好いい。よってHaskellは格好いい。

と思ったが、Schemeにもpa$というのがあるらしい。(pa$ + 1)とかか。

pa$を使ってtailsを書き直してみよう。

;unfold版
(define (string-tails str) 
  (unfold (pa$ = (string-length str))
          (pa$ string-drop str) 
          (pa$ + 1) 
          0))
;iota+map版
(define (string-tails str) 
  (map (pa$ string-drop str) 
       (iota (string-length str)))) 

短くはなったが、こんなコード、慣れてないと絶対読めんな(笑)。