10 Scheme One Liners to Impress Your Friends
http://d.hatena.ne.jp/y2q_actionman/20110607/p1 のパクりを(n)moshで。
読み方
(import ...)はライブラリの読み込みでプログラム本体では無いです。(Rubyのrequireのような。)
SRFI-xというのは、JavaのJSRとかPythonのPEPのようなもので、番号の付いた言語仕様。moshにもいくつかのメジャーなSRFIが収録されています。
moshは今のところ、起動直後では殆ど何もできません。このへんはhigeponと意見の合ってないところで、個人的にはココに挙げるような手続きは全部preloadしちゃって良いと思っていたりします(REPL上では)。
1. Multiple Each Item in a List by 2
SRFI-42のlist-ecを使うのが一番単純。
(import (srfi :42)) (list-ec (: n 1 11) (* n 2))
もちろん出題意図通り解くならmapでできる。mapはScheme標準で入っているが、iotaはSRFI-1に収録されている。(iota 10 1)でリスト(1 2 3 4 5 6 7 8 9 10)の意味。
(import (srfi :1)) (map (^n (* n 2)) (iota 10 1))
mapの中の^nはGaucheから借りてきた表記で、(lambda (n) ...)の意味。moshではこの表記は(shorten)ライブラリに収録されている。
2. Sum a List of Numbers
SRFI-42にsum-ecがあるのでそれで一発。
(import (srfi :42)) (sum-ec (: n 1000) n)
問題の書き方の通りに解くならapplyを使う。
(apply + (iota 1000))
3. Verify if Exists in a String
(import (srfi :13) (srfi :1) (srfi :26)) (define words '("scala" "akka" "play framework" "sbt" "typesafe")) (any (^e (any (cut string=? <> e) words)) (string-tokenize "This is an example tweet talking about scala and sbt."))
うーむ複雑だ。。文字列を空白で区切るstring-tokenizeはSRFI-13、anyはSRFI-1、anyの中で使っているcutはSRFI-26。
4. Read in a File
(import (yuni util files)) (file->string-list "data.txt")
ライブラリ(yuni util files)にfile→string-list手続きを入れてある。実はmosh自体にもこの手続きがあるが、命名に一貫性が無いのであまりオススメしない。
5. Happy Birthday to You!
(import (srfi :48) (srfi :42)) (do-ec (: n 4) (format #t "Happy Birthday ~a\n" (if (= n 2) "dear Tony" "to You")))
単純な繰り返し実行はSRFI-42のdo-ec、printfのようなフォーマット出力はSRFI-48のformat。
moshにはネイティブのformatも有るが、移植性が無いのであまりオススメしない。
6. Filter list of numbers
Scheme標準の手続きとしてpartitionが有るのでこれを使う。
(import (srfi :26)) (partition (cut > <> 60) '(49 58 76 82 88 90))
partitionは普通の手続きとちがって2つの値を返す。なので、実際に値を使うときはlet-valuesやSRFI-8のreceiveを使う必要がある。
7. Fetch and Parse an XML web service
(import (yuni lib ssax parsing) (http) (srfi :8)) (receive (str status headers) (http-get->utf8 "http://search.twitter.com/search.atom?&q=scala") (ssax:xml->sxml (open-string-input-port str) '()))
実はmoshにはこっそりSSAXが入っている。なので、XMLを普通のS式に変換して取り扱うことができる。
http経由でURLを取得するにはhttpライブラリを使う。http-get→utf8という名前だが、実際には文字列を返すので注意。(R6RSの手続きでは、utf8は基本的にutf8表現のbytevectorを表す)
みづらいならpp(pretty-print)を使う。
(import (yuni lib ssax parsing) (http) (srfi :8) (mosh pp)) (receive (str _ __) (http-get->utf8 "http://search.twitter.com/search.atom?&q=scala") (pp (ssax:xml->sxml (open-string-input-port str) '())))
8. Find minimum (or maximum) in a List
(fold-left min 14 '(35 -7 46 98)) (fold-left max 14 '(35 -7 46 98))
これはScheme標準だけでできる。リストの先頭14を初期値とするために外に出している。
- 追記
素直にSRFI-1のreduce使えという声も多いので:
(reduce min #f '(14 37 -7 46 98))
reduceは、(fold-left proc (car L) (cdr L))のように使える。ただ、空リストを渡したときに結果が不定にならないように"空リストを渡したときの結果"を明示的に与える必要がある。
10. Sieve of Eratosthenes
うーん。。この手のはスムースに書けない。Ruby版( http://programmingzen.com/2011/06/02/10-ruby-one-liners-to-impress-your-friends/ )のストレートな移植。
(import (srfi :1)) (let loop ((index 0) (primes (iota 100 2))) (if (<= (expt (list-ref primes index) 2) (car (reverse primes))) (loop (+ index 1) (let ((prime (list-ref primes index))) (filter (^x (or (= prime x) (not (= 0 (mod x prime))))) primes))) primes))