-
Notifications
You must be signed in to change notification settings - Fork 5
Learn Try Scheme
Code from various sources that works directly with the interpreter:
The standard objects are
#f for false
#t for true
but in logical expressions (if
, cond
, and
, or
, when
, unless
, do
), all values except #f
are treated as true.
A symbol is like an ABAP global field-symbols of type ANY
(define pi 3.1415926535897932384626433832795)
;; alternative definition of pi: (define pi (* 4 (atan 1)))
(define a 1)
(define b 2)
Evaluate a symbol
a
=> 1
x
=> Eval: Symbol x is unbound
There are fewer restrictions on a symbol's name
(define ! not)
=> !
(! #f)
=> #t
; multiple dots as an identifier
(define ... "three dots")
=> ...
...
=> "three dots"
Assignment
(define game-over #f)
(set! game-over #t)
A single character can be specified as
#\a
A string is a group of characters enclosed in double quotation marks.
;; valid string: "I am a string"
(display "Hello World")
=> Hello World
Numbers are arranged into a tower of subtypes in which each level is a subset of the level above it:
- number
- complex number 0+4i, 20.0-0.0i with a real part and an imaginary part, where i is the square root of -1.
- real number 3.141492, -1.344e+23, #inf.0, +nan.0 1.6f0
- rational number 4/5, -1/3, 0.25, 1/1
- integer 1, 1.0, 1e10 For example, 3 is an integer. Therefore 3 is also a rational, a real, and a complex number.
Scheme number is exact if it was written as an exact constant or was derived from exact numbers using only exact operations. A number is inexact if it was written as an inexact constant, if it was derived using inexact ingredients, or if it was derived using inexact operations. Thus inexactness is a contagious property of a number. An exact complex number has an exact real part and an exact imaginary part; all other complex numbers are inexact complex numbers.
Note that case is not signicant in numerical constants. A number can be written in binary, octal, decimal, or hexadecimal by the use of a radix prefix. The radix prefixes are #b (binary), #o (octal), #d (decimal), and #x (hexadecimal). With no radix prefix, a number is assumed to be expressed in decimal.
A numerical constant can be specified to be either exact by prefix #e or to be inexact by prefix #i. An exactness prefix can appear before or after any radix prefix that is used. If the written representation of a number has no exactness prefix, the constant is inexact if it contains a decimal point or an exponent. Otherwise, it is exact.
The exponent marker is e, but can be replaced by s, f, d or l (short, single, double, long) for compatibility with other Schemes, although the indicated precision is not used.
LISP uses prefix notation. The ABAP expression a * ( b + c ) / d
will be written as (/ (* a (+ b c) ) d)
(+ 1 2)
=> 3
(+ 1 'foo)
=> Eval: foo is not a number in [+]
; Rational
(+ 2/5 10/6)
=> 31/15
; infix notation is (60 * 9 / 5) + 32
(+ (* (/ 9 5) 60) 32)
=> 140
; infix 2 * cos( 0 ) * ( 4 + 6 )
(* 2 (cos 0) (+ 4 6))
=> 20
(+ 3 (* 4 5))
=> 23
; assumes we have defined a and b as symbols above
(list a b)
=> ( 1 2 )
Examples from the Racket Guide:
(length (list "hop" "skip" "jump")) ; count the elements
==> 3
(list-ref (list "hop" "skip" "jump") 0) ; extract by position. Index starts with 0
==> "hop"
(list-ref (list "hop" "skip" "jump") 1)
==> "skip"
(append (list "hop" "skip") (list "jump")) ; combine lists
==> ("hop" "skip" "jump")
(reverse (list "hop" "skip" "jump")) ; reverse order
==> '("jump" "skip" "hop")
(member "fall" (list "hop" "skip" "jump")) ; check for an element
==> #f
(define c '(1 2 3 4))
=> c
(set-cdr! (cddr c) c)
=> '()
c
=> #0 = ( 1 2 3 . #0# )
(vector 'a 'b)
=> #( a b )
;; Functions
;; (define (function_name arguments)
;; ... function body ... )
;; ... body ... )
(define (f n)
(+ n 10) )
=> f
(f 5)
=> 15
;; the quote function - the argument is NOT evaluated
;; it is kept as a LIST of argument
(quote (+ 3 (* 4 5)) )
=> (+ 3 (* 4 5))
;; the single quotation mark = quote function
'(+ 3 (* 4 5))
=> (+ 3 (* 4 5))
and begin case cond define do if else lambda let let* letrec or quote set!
Functions that return #t
or #f
. The convention is to use ? as the last character in the name, e.g.
; atom?
(define (atom? x)
(not (or (pair? x) (null? x) (vector? x))))
(define x 3)
=> x
;; x greater or equal to 5?
(<= 5 x )
=> #f
;; x less or equal to 16?
(<= x 16 )
=> #t
;; x between 2 and 16 ?
(<= 2 x 16 )
=> #t
;; alternative
(and (<= 2 x ) (<= x 16))
(let (declarations)
... body.. )
surround the entire list of declarations with matching parentheses or brackets
(let ((a 5)
(b 6))
(+ a b))
=> 11
(let ((x 5))
(let ((x 2)
(y x))
(list y x)))
=> ( 5 2 )
(let ((x 2))
(let ((x 3) (y x))
y))
=> 2
let*
binds in sequence, referencing previously bound local variables
(let ((x 2))
(let* ((x 3) (y x))
y))
=> 3
(let* ((a 5)
(b (+ a 2)))
b)
=> 7
;; https://see.stanford.edu/materials/icsppcs107/30-Scheme-Functions.pdf
;; Function: celsius->fahrenheit
;; -----------------------------
;; Simple conversion function to bring a Celsius
;; degree amount into Fahrenheit.
;;
(define (celsius->fahrenheit celsius)
(+ (* 1.8 celsius) 32))
;; https://see.stanford.edu/materials/icsppcs107/30-Scheme-Functions.pdf
;; Predicate function: _leap-year?_
;; ------------------------------
;; Illustrates the use of the 'or, 'and, and 'not special forms. The question mark after the
;; function name isn't required, it's just customary to include a question mark at the end
;; of a function that returns a true or false.
;;
;; A year is a leap year if it's divisible by 400, or if it's divisible by 4 but not by 100.
;;
(define (leap-year? year)
(or (and (zero? (remainder year 4))
(not (zero? (remainder year 100))))
(zero? (remainder year 400))))
;; abs
(define (abs x)
( (if (< x 0)
-
+ ) x ))
(define x 1)
(define (f x) (g 2))
(define (g y) (+ x y))
(f 5)
=> 3 ; not 7
(define (factorial n)
(if (zero? n)
1
(* n (factorial (- n 1)))))
or
(define factorial
(lambda (n)
(if (= n 0)
1
(* n (factorial (- n 1))))))
or
(define (factorial n)
(apply * (iota n 1)))
;; Square
(define (square x) (* x x))
(square 11)
=> 121
;; Average
(define (average x y)
(/ (+ x y) 2))
(average 23 35)
=> 29
(let ((x 5))
(define foo (lambda (y) (bar x y)))
(define bar (lambda (a b) (+ (* a b) a)))
(foo (+ x 3)))
=> 45
;; reverse list
(define reverse
(lambda (ls)
(let rev ((ls ls) (new '()))
(if (null? ls)
new
(rev (cdr ls) (cons (car ls) new))))))
(define (atom? x) (not (or (pair? x) (null? x) (vector? x))))
(define (flatten x)
(letrec
((f (lambda (x r)
(cond ((null? x) r)
((atom? x) (cons x r))
(else (f (car x)
(f (cdr x) r)))))))
(f x ())))
(flatten '((a) (b (c)) (d (e (f)))))
=> ( a b c d e f )
(define nums (iota 100 1))
(define transformed
(map (lambda (n)
(cond ((= (remainder n 15) 0) "FizzBuzz")
((= (remainder n 5) 0) "Buzz")
((= (remainder n 3) 0) "Fizz")
(else n)))
nums))
(for-each (lambda (n) (display n) (newline))
transformed)
;
; primes
; By Ozan Yigit
;
(define (interval-list m n)
(if (> m n)
'()
(cons m (interval-list (+ 1 m) n))))
(define (sieve l)
(define (remove-multiples n l)
(if (null? l)
'()
(if (= (modulo (car l) n) 0) ; division test
(remove-multiples n (cdr l))
(cons (car l)
(remove-multiples n (cdr l))))))
(if (null? l)
'()
(cons (car l)
(sieve (remove-multiples (car l) (cdr l))))))
(define (primes<= n)
(sieve (interval-list 2 n)))
Now execute (primes<= 300)
;; Square Root
;; https://mitpress.mit.edu/sicp/chapter1/node9.html
(define (sqrt x)
(sqrt-iter 1.0 x))
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x)))
(define (good-enough? guess x)
(< (abs (- (square guess) x)) 0.001))
(define (improve guess x)
(average guess (/ x guess)))
(define (quadratic-formula a b c)
;; find the roots x of a quadratic equation a x**2 + b * x + c = 0
(let ([minusb (- 0 b)]
[radical (sqrt (- (* b b) (* 4 (* a c))))]
[divisor (* 2 a)])
(let ([root1 (/ (+ minusb radical) divisor)]
[root2 (/ (- minusb radical) divisor)])
; create a pair with both solutions
(cons root1 root2))))
now test
(quadratic-formula 2 -4 -6)
=> ( 3 . -1 )
if you have been using the sqrt approximation above, you will get something like
=> ( 3.001286994470244717463540664936568 . -1.001286994470244717463540664936566 )
instead.
;----------------------------------------------------------
;; guess my number between 1 and 100
(define *big* 100)
(define *small* 1)
(define (guess) (round (/ (+ *big* *small*) 2)) )
(define (larger) (set! *small* (+ 1 (guess))) (guess))
(define (smaller) (set! *big* (- (guess) 1)) (guess))
(define (restart) (set! *big* 100) (set! *small* 1) (guess))
; my number is 16 - the logic needs 7 steps
(restart) ; 51
(smaller) ; 26
(smaller) ; 13
(larger) ; 20
(smaller) ; 17
(smaller) ; 15
(larger) ; 16
;--------- now your number
(restart) ; 51
IO test © 1996 by A. Aaby
The purpose of the following function is to help balance a checkbook. The function prompts the user for an initial balance. Then it enters the loop in which it requests a number from the user, subtracts it from the current balance, and keeps track of the new balance. Deposits are entered by inputting a negative number. Entering zero (0) causes the procedure to terminate and print the final balance.
(define checkbook (lambda ()
; This check book balancing program was written to illustrate
; i/o in Scheme. It uses the purely functional part of Scheme.
; These definitions are local to checkbook
(letrec
; These strings are used as prompts
((IB "Enter initial balance: ")
(AT "Enter transaction (- for withdrawal): ")
(FB "Your final balance is: ")
; This function displays a prompt then returns a value read.
(prompt-read (lambda (Prompt)
(display Prompt)
(read)))
; This function recursively computes the new balance given
; an initial balance init and a new value t.
; Termination occurs when the new value is 0.
(newbal (lambda (Init t)
(if (= t 0)
(list FB Init)
(transaction (+ Init t)))))
; This function prompts for and reads the next
; transaction and passes the information to newbal
(transaction (lambda (Init)
(newbal Init (prompt-read AT)))))
; This is the body of checkbook; it prompts for the starting balance
(transaction (prompt-read IB)))))
Now call (checkbook)
A Quine
((lambda (x)
(list x (list (quote quote) x)))
(quote (lambda (x)
(list x (list (quote quote) x)))))
;; http://www.brics.dk/RS/03/20/BRICS-RS-03-20.pdf
;; A staged quadratic-time string matcher
(define (main pattern text)
(match pattern text 0 0))
(define (match pattern text j k)
(if (= (string-length pattern) j)
(- k j)
(if (= (string-length text) k)
-1
(compare pattern text j k))))
;; Backtracking also using one character of negative information
(define (compare pattern text j k)
(if (equal? (string-ref text k)
(string-ref pattern j))
(match pattern text (+ j 1) (+ k 1))
(let ([s (rematch-neg pattern j)])
(if (= s -1)
(match pattern text 0 (+ k 1))
(compare pattern text s k)))))
(define (rematch-neg pattern i)
(if (= i 0)
-1
(let ([j (rematch pattern i)])
(if (equal? (string-ref pattern j)
(string-ref pattern i))
(rematch-neg pattern j)
j))))
; (define (compare pattern text j k)
; (if (equal? (string-ref pattern j) (string-ref text k))
; (match pattern text (+ j 1) (+ k 1))
; (let ([s (rematch pattern j)])
; (if (= s -1)
; (match pattern text 0 (+ k 1))
; (compare pattern text s k)))))
;; Compositional backtracking suitable for fast partial evaluation
(define (rematch pattern i)
(if (= i 0)
-1
(letrec ([try-subproblem
(lambda (j)
(if (= j -1)
0
(if (equal? (string-ref pattern j)
(string-ref pattern (- i 1)))
(+ j 1)
(try-subproblem (rematch pattern j)))))])
(try-subproblem (rematch pattern (- i 1))))))
More Examples from https://github.com/hmgle/yascm
https://cs.gmu.edu/~white/CS363/Scheme/SchemeSamples.html
https://github.com/hmgle/yascm/blob/master/tests/tests.scm