可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How to create a list of consecutive numbers in Scheme?
In Python to create a list of integers from 1 to 10 would be range(1,11)
. Is there an equivalent for Scheme?
mzscheme --version
gives Welcome to Racket v5.2.1.
Edit: Per https://stackoverflow.com/a/7144310/596361 to implement range functionality, this code is needed:
#lang racket
(require srfi/1)
(iota 5 1)
回答1:
Look for iota (as defined in SRFI-1).
Example: (iota 10 1) gives 10 consecutive integers starting from 1 (instead of the default of 0).
iota doesn't take the same arguments as range but it duplicates all the functionality - ascending ranges, descending ranges, starting from 0 if only one bound is given, ability to specify the interval.
回答2:
Here's a version which does an ascending range if the first number is lower or a descending range if it is higher:
(define range
(lambda (n m)
(cond
((= n m) (list n))
(else (cons n (range ((if (< n m) + -) n 1) m))))))
And here's an improved version which can take 1 or 2 arguments; if only one is given, it does a range from 0 to the given number:
(define range
(lambda (n . m)
(let
((n (if (null? m) 0 n)) (m (if (null? m) n (car m))))
(cond
((= n m) (list n))
(else (cons n (range ((if (< n m) + -) n 1) m)))))))
回答3:
If there's nothing built-in, it's trivial to write your own:
(define (range first last)
(if (>= first last)
'()
(cons first (range (+ first 1) last))))
Online scheme evaluator: http://eval.ironscheme.net/?id=71
回答4:
There is a built-in range function in Racket that behaves like that of Python.
> (range 10)
'(0 1 2 3 4 5 6 7 8 9)
回答5:
I'm just elevating @Ankur's comment to an answer. In Racket, you have "in-range":
#lang racket
(in-range 7) ;; produces #<stream>
;; used in a loop:
(for/list ([i (in-range 7)])
i)
;; produces (list 0 1 2 3 4 5 6)
;; and, for the lazy among us:
(for/list ([i 7])
i)
;; produces the same
It can also accept a lower limit, an increment (including negative), etc.
回答6:
Not finding what I wanted and not wanting to have to use an external package, I ended up writing my own version which differs from the python version (hopefully improving on it). If you think it is really inefficient and can improve on it, please do.
;; A version of range taking the form (range [[first] last [[step]]] ).
;; It takes negative numbers and corrects STEP to the same direction
;; as FIRST to LAST then returns a list starting from FIRST and
;; ending before LAST
(define (range . args)
(case (length args)
( (0) '())
( (1) (range 0 (car args) (if (negative? (car args)) -1 1)))
( (2) (range (car args) (cadr args)
(if (>= (car args) (cadr args)) -1 1)))
( (3) (let* ((start (car args)) (end (cadr args))
(step (if (> start end)
(- (abs (caddr args)))
(abs (caddr args)))))
(let loop ((x start) (xs '()))
(cond ((and (>= end start) (<= (abs end) (abs x)))
(reverse xs))
((and (<= end start) (>= (abs end) (abs x)))
(reverse xs))
(else (loop (+ x step) (cons x xs)))))))
(else (error 'range "too many arguments"))))
; (else (display "ERROR: range too many arguments") (newline)))) ;;r4rs
;; (range-inc [[first] last [[step]]] ) includes LAST in the returned range
(define (range-inc . args)
(case (length args)
( (0) '())
( (1) (append (range (car args)) args))
( (2) (append (range (car args) (cadr args)) (cdr args)))
( (3) (append (range (car args) (cadr args) (caddr args))
(list (cadr args))))
(else (error 'range "too many arguments"))))
; (else (display "ERROR: range too many arguments") (newline)))) ;;r4rs
Note I wrote a common lisp version as well
回答7:
Following a comment by Germán Diago I made a pure functional lazy version (i.e. stream) for this. It can construct a range stream of any size that your Scheme implementation can handle in constant time as well as access the current element and advance the stream, also in constant time.
(define ^range
(lambda (x y getter)
(op x y getter)))
(define EOS ; End of stream for finite streams
(^range '() '() (lambda () EOS)))
(define range
(lambda (x . y) ; if y < x then stream is infinite
(let ((x (if (null? y) 0 x))
(y (if (null? y) x (car y))))
(^range x y (lambda ()
(if (= x y) EOS
(range (+ x 1) y)))))))
(define get ; Get current element
(lambda (r)
(r (lambda (x y g) x))))
(define next ; Get stream for next element
(lambda (r)
(r (lambda (x y g) (g)))))
Using this code:
> (define r (range 1 3))
> (get r)
1
> (get (next r))
2
> (get (next (next r)))
3
> (get (next (next (next r)))) ; EOS
()