Pythonのrange関数をJavaScriptで再帰を使って実装してみたものをGaucheに移植してみた
今朝投稿した、Pythonのrange関数をJavaScriptで再帰を使って実装してみた - あと味の続き。
JavaScript版は基本的な関数で実装したので、おそらくGauche(Scheme)にも簡単に移植できると思って取り組んでみたものの、正直、慣れてなさすぎて超大変でした。
対してコメントもできませんが、もうちょっとGaucheらしいスマートな実装方法もあるのかしら。
元になったJavaScriptのコード
function range(start, end, step) { return ( (start === undefined) ? new Error('range expected at least 1 arguments, got 0') : (typeof start !== 'number') ? new Error('range() integer start argument expected, got ' + typeof start) : (end !== undefined && typeof end !== 'number') ? new Error('range() integer end argument expected, got ' + typeof end) : (step !== undefined && typeof step !== 'number') ? new Error('range() integer step argument expected, got ' + typeof step) : (step === 0) ? new Error('range() step argument must not be zero') : (arguments[3]) ? new Error('range expected at most 3 arguments, got ' + arguments.length) : (function(start, end, step, list) { return ( (step > 0 && start < end || step < 0 && start > end) ? arguments.callee(start+step, end, step, list.concat(start)) : list ); })(end === undefined ? 0 : start, end === undefined ? start : end, step === undefined ? 1 : step ,[]) ); }
Gaucheのコード
(define (range start . args) (let-optionals* args ((end '()) (step '())) (define (range2 start end step lis) (cond [(or (and (> step 0) (< start end)) (and (< step 0) (> start end))) (range2 (+ start step) end step (append lis (cons start '())))] [else lis])) (cond [(eq? (number? start) #f) (error "range() integer start argument expected, got " (class-of start))] [(and (eq? (null? end) #f) (eq? (number? end) #f)) (error "range() integer end argument expected, got " (class-of end))] [(and (eq? (null? step) #f) (eq? (number? step) #f)) (error "range() integer step argument expected, got " (class-of step))] [(eq? step 0) (error "range() step argument must not be zero")] [(< 2 (length args)) (error "range expected at most 3 arguments, got " (+ 1 (length args)))] [else (range2 (if (null? end) 0 start) (if (null? end) start end) (if (null? step) 1 step) '())])))
さっそく省略可能引数の扱い方がわからずハマりました。後、リストの構造がJavaScriptと違って再帰的なので、appendの引数の部分もハマりました。
その他は割とスムーズに移植できた気がします。JavaScript版に比べて前置記法が多少コードを見やすくしてくれている気もします。
Lispを使って、自分で考えた何かを作ったのは初めての経験なので、動いて感動した。