nekoTheShadow’s diary

IT業界の片隅でひっそり生きるシステムエンジニアです(´・ω・`)

「インデックス付きmap」が必要だったので……

 Rubyでいうところのmap.with_index、すなわち「インデックス付きmap」がSchemeソースコードを書いている最中に必要だったので、マクロにより実装しました。

; procの第1引数にインデックス(0..*)が入るようなmap
; リストは1つ以上指定できるが、ひとつでもリストが最後に到達したらそこで計算を終える
; ex. (map-with-index (cut list <...>) '('a 'b 'c)) => ((0 'a) (1 'b) (2 'c))
; ex. (map-with-index (cut list <...>) '('a 'b 'c) '('e 'f 'g)) => ((0 'a 'e) (1 'b 'f) (2 'c 'g))
; ex. (map-with-index (cut list <...>) '('a 'b 'c) '('e 'f )) => ((0 'a 'e) (1 'b 'f))
(define-syntax map-with-index
    (syntax-rules ()
        ((_ proc ls1 ls2 ...)
            (map proc (iota (length ls1)) ls1 ls2 ...))))

 「なぜ関数ではなくマクロで実装したのか」と訊かれると困ってしまう……。「なんとなく」としか答えようがありません……。

 ちなみにfoldのほうもマクロで書いたので、こちらも一応紹介しておきます(Rubyだとinject.with_indexになりますね)。

; procの第1引数にインデックス(0..*)が入るようなfold
; リストは1つ以上指定できるが、ひとつでもリストが最後に到達したらそこで計算を終える
(define-syntax fold-with-index
    (syntax-rules ()
        ((_ proc init ls1 ls2 ...) (fold proc init (iota (length ls1)) ls1 ls2 ...))))

 自分で関数やメソッドを定義した際はかならず、その説明と凡例を書くよう心掛けているのですが、上記のfold-with-indexには説明はあるものの凡例はありません。なぜでしょう。答えは単純。いい例を思いつかなかったから……。反省します(´・ω・`)


2015/11/01追記:具体例ですが暫定案を思いついたのでとりあえず記しておきます。

; procの第1引数にインデックス(0..*)が入るようなfold
; リストは1つ以上指定できるが、ひとつでもリストが最後に到達したらそこで計算を終える
; ex. (fold (lambda (idx val sum) (+ idx val sum)) 0 '(1 2 3))
; ex. (fold (lambda (idx val1 val2 sum) (+ idx val1 val2 sum)) 0 '(1 2) '(1 2 3))
(define-syntax fold-with-index
    (syntax-rules ()
        ((_ proc init ls1 ls2 ...) (fold proc init (iota (length ls1)) ls1 ls2 ...))))