Racket

Личный сайт Go-разработчика из Казани

Racket is a general purpose, multi-paradigm programming language in the Lisp/Scheme family.

1#lang racket ; defines the language we are using 2 3;;; Comments 4 5;; Single line comments start with a semicolon 6 7#| Block comments 8 can span multiple lines and... 9 #| 10 they can be nested! 11 |# 12|# 13 14;; S-expression comments discard the following expression, 15;; useful to comment expressions when debugging 16#; (this expression is discarded) 17 18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 19;; 1. Primitive Datatypes and Operators 20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 21 22;;; Numbers 239999999999999999999999 ; integers 24#b111 ; binary => 7 25#o111 ; octal => 73 26#x111 ; hexadecimal => 273 273.14 ; reals 286.02e+23 291/2 ; rationals 301+2i ; complex numbers 31 32;; Function application is written (f x y z ...) 33;; where f is a function and x, y, z, ... are operands 34;; If you want to create a literal list of data, use ' to stop it from 35;; being evaluated 36'(+ 1 2) ; => (+ 1 2) 37;; Now, some arithmetic operations 38(+ 1 1) ; => 2 39(- 8 1) ; => 7 40(* 10 2) ; => 20 41(expt 2 3) ; => 8 42(quotient 5 2) ; => 2 43(remainder 5 2) ; => 1 44(/ 35 5) ; => 7 45(/ 1 3) ; => 1/3 46(exact->inexact 1/3) ; => 0.3333333333333333 47(+ 1+2i 2-3i) ; => 3-1i 48 49;;; Booleans 50#t ; for true 51#f ; for false -- any value other than #f is true 52(not #t) ; => #f 53(and 0 #f (error "doesn't get here")) ; => #f 54(or #f 0 (error "doesn't get here")) ; => 0 55 56;;; Characters 57#\A ; => #\A 58#\λ ; => #\λ 59#\u03BB ; => #\λ 60 61;;; Strings are fixed-length array of characters. 62"Hello, world!" 63"Benjamin \"Bugsy\" Siegel" ; backslash is an escaping character 64"Foo\tbar\41\x21\u0021\a\r\n" ; includes C escapes, Unicode 65"λx:(μα.α→α).xx" ; can include Unicode characters 66 67;; Strings can be added too! 68(string-append "Hello " "world!") ; => "Hello world!" 69 70;; A string can be treated like a list of characters 71(string-ref "Apple" 0) ; => #\A 72 73;; format can be used to format strings: 74(format "~a can be ~a" "strings" "formatted") 75 76;; Printing is pretty easy 77(printf "I'm Racket. Nice to meet you!\n") 78 79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 80;; 2. Variables 81;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 82;; You can create a variable using define 83;; a variable name can use any character except: ()[]{}",'`;#|\ 84(define some-var 5) 85some-var ; => 5 86 87;; You can also use unicode characters 88(definesubset?) 89(⊆ (set 3 2) (set 1 2 3)) ; => #t 90 91;; Accessing a previously unassigned variable is an exception 92; x ; => x: undefined ... 93 94;; Local binding: `me' is bound to "Bob" only within the (let ...) 95(let ([me "Bob"]) 96 "Alice" 97 me) ; => "Bob" 98 99;; let* is like let, but allows you to use previous bindings in creating later bindings 100(let* ([x 1] 101 [y (+ x 1)]) 102 (* x y)) 103 104;; finally, letrec allows you to define recursive and mutually recursive functions 105(letrec ([is-even? (lambda (n) 106 (or (zero? n) 107 (is-odd? (sub1 n))))] 108 [is-odd? (lambda (n) 109 (and (not (zero? n)) 110 (is-even? (sub1 n))))]) 111 (is-odd? 11)) 112 113;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 114;; 3. Structs and Collections 115;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 116 117;; Structs 118; By default, structs are immutable 119(struct dog (name breed age)) 120(define my-pet 121 (dog "lassie" "collie" 5)) 122my-pet ; => #<dog> 123; returns whether the variable was constructed with the dog constructor 124(dog? my-pet) ; => #t 125; accesses the name field of the variable constructed with the dog constructor 126(dog-name my-pet) ; => "lassie" 127 128; You can explicitly declare a struct to be mutable with the #:mutable option 129(struct rgba-color (red green blue alpha) #:mutable) 130(define burgundy 131 (rgba-color 144 0 32 1.0)) 132(set-rgba-color-green! burgundy 10) 133(rgba-color-green burgundy) ; => 10 134 135;;; Pairs (immutable) 136;; `cons' constructs pairs, `car' and `cdr' extract the first 137;; and second elements 138(cons 1 2) ; => '(1 . 2) 139(car (cons 1 2)) ; => 1 140(cdr (cons 1 2)) ; => 2 141 142;;; Lists 143 144;; Lists are linked-list data structures, made of `cons' pairs and end 145;; with a `null' (or '()) to mark the end of the list 146(cons 1 (cons 2 (cons 3 null))) ; => '(1 2 3) 147;; `list' is a convenience variadic constructor for lists 148(list 1 2 3) ; => '(1 2 3) 149;; a quote can also be used for a literal list value 150'(1 2 3) ; => '(1 2 3) 151;; a quasiquote (represented by the backtick character) with commas 152;; can be used to evaluate functions 153`(1 ,(+ 1 1) 3) ; => '(1 2 3) 154 155;; With lists, car/cdr work slightly differently 156(car '(1 2 3)) ; => 1 157(cdr '(1 2 3)) ; => '(2 3) 158 159;; Racket also has predefined functions on top of car and cdr, to extract parts of a list 160(cadr (list 1 2 3)) ; => 2 161(car (cdr (list 1 2 3))) ; => 2 162 163(cddr (list 1 2 3)) ; => '(3) 164(cdr (cdr (list 1 2 3))) ; => '(3) 165 166(caddr (list 1 2 3)) ; => 3 167(car (cdr (cdr (list 1 2 3)))) ; => 3 168 169;; Can still use `cons' to add an item to the beginning of a list 170(cons 4 '(1 2 3)) ; => '(4 1 2 3) 171 172;; Use `append' to add lists together 173(append '(1 2) '(3 4)) ; => '(1 2 3 4) 174 175;; Lists are a very basic type, so there is a *lot* of functionality for 176;; them, a few examples: 177(map add1 '(1 2 3)) ; => '(2 3 4) 178(map + '(1 2 3) '(10 20 30)) ; => '(11 22 33) 179(filter even? '(1 2 3 4)) ; => '(2 4) 180(count even? '(1 2 3 4)) ; => 2 181(take '(1 2 3 4) 2) ; => '(1 2) 182(drop '(1 2 3 4) 2) ; => '(3 4) 183 184;;; Vectors 185 186;; Vectors are fixed-length arrays 187#(1 2 3) ; => '#(1 2 3) 188 189;; Use `vector-append' to add vectors together 190(vector-append #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6) 191 192;;; Sets 193 194;; Create a set from a list 195(list->set '(1 2 3 1 2 3 3 2 1 3 2 1)) ; => (set 1 2 3) 196 197;; Add a member with `set-add' 198;; (Functional: returns the extended set rather than mutate the input) 199(set-add (set 1 2 3) 4) ; => (set 1 2 3 4) 200 201;; Remove one with `set-remove' 202(set-remove (set 1 2 3) 1) ; => (set 2 3) 203 204;; Test for existence with `set-member?' 205(set-member? (set 1 2 3) 1) ; => #t 206(set-member? (set 1 2 3) 4) ; => #f 207 208;;; Hashes 209 210;; Create an immutable hash table (mutable example below) 211(define m (hash 'a 1 'b 2 'c 3)) 212 213;; Retrieve a value 214(hash-ref m 'a) ; => 1 215 216;; Retrieving a non-present value is an exception 217; (hash-ref m 'd) => no value found 218 219;; You can provide a default value for missing keys 220(hash-ref m 'd 0) ; => 0 221 222;; Use `hash-set' to extend an immutable hash table 223;; (Returns the extended hash instead of mutating it) 224(define m2 (hash-set m 'd 4)) 225m2 ; => '#hash((b . 2) (a . 1) (d . 4) (c . 3)) 226 227;; Remember, these hashes are immutable! 228m ; => '#hash((b . 2) (a . 1) (c . 3)) <-- no `d' 229 230;; Use `hash-remove' to remove keys (functional too) 231(hash-remove m 'a) ; => '#hash((b . 2) (c . 3)) 232 233;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 234;; 4. Functions 235;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 236 237;; Use `lambda' to create functions. 238;; A function always returns the value of its last expression 239(lambda () "Hello World") ; => #<procedure> 240;; Can also use a unicode `λ' 241(λ () "Hello World") ; => same function 242 243;; Use parens to call all functions, including a lambda expression 244((lambda () "Hello World")) ; => "Hello World" 245((λ () "Hello World")) ; => "Hello World" 246 247;; Assign a function to a var 248(define hello-world (lambda () "Hello World")) 249(hello-world) ; => "Hello World" 250 251;; You can shorten this using the function definition syntactic sugar: 252(define (hello-world2) "Hello World") 253 254;; The () in the above is the list of arguments for the function 255(define hello 256 (lambda (name) 257 (string-append "Hello " name))) 258(hello "Steve") ; => "Hello Steve" 259;; ... or equivalently, using a sugared definition: 260(define (hello2 name) 261 (string-append "Hello " name)) 262 263;; You can have multi-variadic functions too, using `case-lambda' 264(define hello3 265 (case-lambda 266 [() "Hello World"] 267 [(name) (string-append "Hello " name)])) 268(hello3 "Jake") ; => "Hello Jake" 269(hello3) ; => "Hello World" 270;; ... or specify optional arguments with a default value expression 271(define (hello4 [name "World"]) 272 (string-append "Hello " name)) 273 274;; Functions can pack extra arguments up in a list 275(define (count-args . args) 276 (format "You passed ~a args: ~a" (length args) args)) 277(count-args 1 2 3) ; => "You passed 3 args: (1 2 3)" 278;; ... or with the unsugared `lambda' form: 279(define count-args2 280 (lambda args 281 (format "You passed ~a args: ~a" (length args) args))) 282 283;; You can mix regular and packed arguments 284(define (hello-count name . args) 285 (format "Hello ~a, you passed ~a extra args" name (length args))) 286(hello-count "Finn" 1 2 3) 287; => "Hello Finn, you passed 3 extra args" 288;; ... unsugared: 289(define hello-count2 290 (lambda (name . args) 291 (format "Hello ~a, you passed ~a extra args" name (length args)))) 292 293;; And with keywords 294(define (hello-k #:name [name "World"] #:greeting [g "Hello"] . args) 295 (format "~a ~a, ~a extra args" g name (length args))) 296(hello-k) ; => "Hello World, 0 extra args" 297(hello-k 1 2 3) ; => "Hello World, 3 extra args" 298(hello-k #:greeting "Hi") ; => "Hi World, 0 extra args" 299(hello-k #:name "Finn" #:greeting "Hey") ; => "Hey Finn, 0 extra args" 300(hello-k 1 2 3 #:greeting "Hi" #:name "Finn" 4 5 6) 301 ; => "Hi Finn, 6 extra args" 302 303;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 304;; 5. Equality 305;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 306 307;; for numbers use `=' 308(= 3 3.0) ; => #t 309(= 2 1) ; => #f 310 311;; `eq?' returns #t if 2 arguments refer to the same object (in memory), 312;; #f otherwise. 313;; In other words, it's a simple pointer comparison. 314(eq? '() '()) ; => #t, since there exists only one empty list in memory 315(let ([x '()] [y '()]) 316 (eq? x y)) ; => #t, same as above 317 318(eq? (list 3) (list 3)) ; => #f 319(let ([x (list 3)] [y (list 3)]) 320 (eq? x y)) ; => #f — not the same list in memory! 321 322(let* ([x (list 3)] [y x]) 323 (eq? x y)) ; => #t, since x and y now point to the same stuff 324 325(eq? 'yes 'yes) ; => #t 326(eq? 'yes 'no) ; => #f 327 328(eq? 3 3) ; => #t — be careful here 329 ; It’s better to use `=' for number comparisons. 330(eq? 3 3.0) ; => #f 331 332(eq? (expt 2 100) (expt 2 100)) ; => #f 333(eq? (integer->char 955) (integer->char 955)) ; => #f 334 335(eq? (string-append "foo" "bar") (string-append "foo" "bar")) ; => #f 336 337;; `eqv?' supports the comparison of number and character datatypes. 338;; for other datatypes, `eqv?' and `eq?' return the same result. 339(eqv? 3 3.0) ; => #f 340(eqv? (expt 2 100) (expt 2 100)) ; => #t 341(eqv? (integer->char 955) (integer->char 955)) ; => #t 342 343(eqv? (string-append "foo" "bar") (string-append "foo" "bar")) ; => #f 344 345;; `equal?' supports the comparison of the following datatypes: 346;; strings, byte strings, pairs, mutable pairs, vectors, boxes, 347;; hash tables, and inspectable structures. 348;; for other datatypes, `equal?' and `eqv?' return the same result. 349(equal? 3 3.0) ; => #f 350(equal? (string-append "foo" "bar") (string-append "foo" "bar")) ; => #t 351(equal? (list 3) (list 3)) ; => #t 352 353;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 354;; 6. Control Flow 355;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 356 357;;; Conditionals 358 359(if #t ; test expression 360 "this is true" ; then expression 361 "this is false") ; else expression 362; => "this is true" 363 364;; In conditionals, all non-#f values are treated as true 365(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(Groucho Zeppo) 366(if (member 'Groucho '(Harpo Groucho Zeppo)) 367 'yep 368 'nope) 369; => 'yep 370 371;; `cond' chains a series of tests to select a result 372(cond [(> 2 2) (error "wrong!")] 373 [(< 2 2) (error "wrong again!")] 374 [else 'ok]) ; => 'ok 375 376;;; Pattern Matching 377 378(define (fizzbuzz? n) 379 (match (list (remainder n 3) (remainder n 5)) 380 [(list 0 0) 'fizzbuzz] 381 [(list 0 _) 'fizz] 382 [(list _ 0) 'buzz] 383 [_ #f])) 384 385(fizzbuzz? 15) ; => 'fizzbuzz 386(fizzbuzz? 37) ; => #f 387 388;;; Loops 389 390;; Looping can be done through (tail-) recursion 391(define (loop i) 392 (when (< i 10) 393 (printf "i=~a\n" i) 394 (loop (add1 i)))) 395(loop 5) ; => i=5, i=6, ... 396 397;; Similarly, with a named let 398(let loop ([i 0]) 399 (when (< i 10) 400 (printf "i=~a\n" i) 401 (loop (add1 i)))) ; => i=0, i=1, ... 402 403;; See below how to add a new `loop' form, but Racket already has a very 404;; flexible `for' form for loops: 405(for ([i 10]) 406 (printf "i=~a\n" i)) ; => i=0, i=1, ... 407(for ([i (in-range 5 10)]) 408 (printf "i=~a\n" i)) ; => i=5, i=6, ... 409 410;;; Iteration Over Other Sequences 411;; `for' allows iteration over many other kinds of sequences: 412;; lists, vectors, strings, sets, hash tables, etc... 413 414(for ([i (in-list '(l i s t))]) 415 (displayln i)) 416 417(for ([i (in-vector #(v e c t o r))]) 418 (displayln i)) 419 420(for ([i (in-string "string")]) 421 (displayln i)) 422 423(for ([i (in-set (set 'x 'y 'z))]) 424 (displayln i)) 425 426(for ([(k v) (in-hash (hash 'a 1 'b 2 'c 3))]) 427 (printf "key:~a value:~a\n" k v)) 428 429;;; More Complex Iterations 430 431;; Parallel scan of multiple sequences (stops on shortest) 432(for ([i 10] [j '(x y z)]) 433 (printf "~a:~a\n" i j)) 434; => 0:x 1:y 2:z 435 436;; Nested loops 437(for* ([i 2] [j '(x y z)]) 438 (printf "~a:~a\n" i j)) 439; => 0:x, 0:y, 0:z, 1:x, 1:y, 1:z 440 441;; Conditions 442(for ([i 1000] 443 #:when (> i 5) 444 #:unless (odd? i) 445 #:break (> i 10)) 446 (printf "i=~a\n" i)) 447; => i=6, i=8, i=10 448 449;;; Comprehensions 450;; Very similar to `for' loops -- just collect the results 451 452(for/list ([i '(1 2 3)]) 453 (add1 i)) ; => '(2 3 4) 454 455(for/list ([i '(1 2 3)] #:when (even? i)) 456 i) ; => '(2) 457 458(for/list ([i 10] [j '(x y z)]) 459 (list i j)) ; => '((0 x) (1 y) (2 z)) 460 461(for/list ([i 1000] #:when (> i 5) #:unless (odd? i) #:break (> i 10)) 462 i) ; => '(6 8 10) 463 464(for/hash ([i '(1 2 3)]) 465 (values i (number->string i))) 466; => '#hash((1 . "1") (2 . "2") (3 . "3")) 467 468;; There are many kinds of other built-in ways to collect loop values: 469(for/sum ([i 10]) (* i i)) ; => 285 470(for/product ([i (in-range 1 11)]) (* i i)) ; => 13168189440000 471(for/and ([i 10] [j (in-range 10 20)]) (< i j)) ; => #t 472(for/or ([i 10] [j (in-range 0 20 2)]) (= i j)) ; => #t 473;; And to use any arbitrary combination, use `for/fold' 474(for/fold ([sum 0]) ([i '(1 2 3 4)]) (+ sum i)) ; => 10 475;; (This can often replace common imperative loops) 476 477;;; Exceptions 478 479;; To catch exceptions, use the `with-handlers' form 480(with-handlers ([exn:fail? (lambda (exn) 999)]) 481 (+ 1 "2")) ; => 999 482(with-handlers ([exn:break? (lambda (exn) "no time")]) 483 (sleep 3) 484 "phew") ; => "phew", but if you break it => "no time" 485 486;; Use `raise' to throw exceptions or any other value 487(with-handlers ([number? ; catch numeric values raised 488 identity]) ; return them as plain values 489 (+ 1 (raise 2))) ; => 2 490 491;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 492;; 7. Mutation 493;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 494 495;; Use `set!' to assign a new value to an existing variable 496(define n 5) 497(set! n (add1 n)) 498n ; => 6 499 500;; Use boxes for explicitly mutable values (similar to pointers or 501;; references in other languages) 502(define n* (box 5)) 503(set-box! n* (add1 (unbox n*))) 504(unbox n*) ; => 6 505 506;; Many Racket datatypes are immutable (pairs, lists, etc), some come in 507;; both mutable and immutable flavors (strings, vectors, hash tables, 508;; etc...) 509 510;; Use `vector' or `make-vector' to create mutable vectors 511(define vec (vector 2 2 3 4)) 512(define wall (make-vector 100 'bottle-of-beer)) 513;; Use vector-set! to update a slot 514(vector-set! vec 0 1) 515(vector-set! wall 99 'down) 516vec ; => #(1 2 3 4) 517 518;; Create an empty mutable hash table and manipulate it 519(define m3 (make-hash)) 520(hash-set! m3 'a 1) 521(hash-set! m3 'b 2) 522(hash-set! m3 'c 3) 523(hash-ref m3 'a) ; => 1 524(hash-ref m3 'd 0) ; => 0 525(hash-remove! m3 'a) 526 527;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 528;; 8. Modules 529;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 530 531;; Modules let you organize code into multiple files and reusable 532;; libraries; here we use sub-modules, nested in the whole module that 533;; this text makes (starting from the "#lang" line) 534 535(module cake racket/base ; define a `cake' module based on racket/base 536 537 (provide print-cake) ; function exported by the module 538 539 (define (print-cake n) 540 (show " ~a " n #\.) 541 (show " .-~a-. " n #\|) 542 (show " | ~a | " n #\space) 543 (show "---~a---" n #\-)) 544 545 (define (show fmt n ch) ; internal function 546 (printf fmt (make-string n ch)) 547 (newline))) 548 549;; Use `require' to get all `provide'd names from a module 550(require 'cake) ; the ' is for a local submodule 551(print-cake 3) 552; (show "~a" 1 #\A) ; => error, `show' was not exported 553 554;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 555;; 9. Classes and Objects 556;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 557 558;; Create a class fish% (-% is idiomatic for class bindings) 559(define fish% 560 (class object% 561 (init size) ; initialization argument 562 (super-new) ; superclass initialization 563 ;; Field 564 (define current-size size) 565 ;; Public methods 566 (define/public (get-size) 567 current-size) 568 (define/public (grow amt) 569 (set! current-size (+ amt current-size))) 570 (define/public (eat other-fish) 571 (grow (send other-fish get-size))))) 572 573;; Create an instance of fish% 574(define charlie 575 (new fish% [size 10])) 576 577;; Use `send' to call an object's methods 578(send charlie get-size) ; => 10 579(send charlie grow 6) 580(send charlie get-size) ; => 16 581 582;; `fish%' is a plain "first class" value, which can get us mixins 583(define (add-color c%) 584 (class c% 585 (init color) 586 (super-new) 587 (define my-color color) 588 (define/public (get-color) my-color))) 589(define colored-fish% (add-color fish%)) 590(define charlie2 (new colored-fish% [size 10] [color 'red])) 591(send charlie2 get-color) 592;; or, with no names: 593(send (new (add-color fish%) [size 10] [color 'red]) get-color) 594 595;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 596;; 10. Macros 597;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 598 599;; Macros let you extend the syntax of the language 600 601;; Let's add a while loop 602(define-syntax-rule (while condition body ...) 603 (let loop () 604 (when condition 605 body ... 606 (loop)))) 607 608(let ([i 0]) 609 (while (< i 10) 610 (displayln i) 611 (set! i (add1 i)))) 612 613;; Macros are hygienic, you cannot clobber existing variables! 614(define-syntax-rule (swap! x y) ; -! is idiomatic for mutation 615 (let ([tmp x]) 616 (set! x y) 617 (set! y tmp))) 618 619(define tmp 2) 620(define other 3) 621(swap! tmp other) 622(printf "tmp = ~a; other = ~a\n" tmp other) 623;; The variable `tmp` is renamed to `tmp_1` 624;; in order to avoid name conflict 625;; (let ([tmp_1 tmp]) 626;; (set! tmp other) 627;; (set! other tmp_1)) 628 629;; But they are still code transformations, for example: 630(define-syntax-rule (bad-while condition body ...) 631 (when condition 632 body ... 633 (bad-while condition body ...))) 634;; this macro is broken: it generates infinite code, if you try to use 635;; it, the compiler will get in an infinite loop 636 637;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 638;; 11. Contracts 639;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 640 641;; Contracts impose constraints on values exported from modules 642 643(module bank-account racket 644 (provide (contract-out 645 [deposit (-> positive? any)] ; amounts are always positive 646 [balance (-> positive?)])) 647 648 (define amount 0) 649 (define (deposit a) (set! amount (+ amount a))) 650 (define (balance) amount)) 651 652(require 'bank-account) 653(deposit 5) 654 655(balance) ; => 5 656 657;; Clients that attempt to deposit a non-positive amount are blamed 658;; (deposit -5) ; => deposit: contract violation 659;; expected: positive? 660;; given: -5 661;; more details.... 662 663;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 664;; 12. Input & output 665;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 666 667;; Racket has this concept of "port", which is very similar to file 668;; descriptors in other languages 669 670;; Open "/tmp/tmp.txt" and write "Hello World" 671;; This would trigger an error if the file's already existed 672(define out-port (open-output-file "/tmp/tmp.txt")) 673(displayln "Hello World" out-port) 674(close-output-port out-port) 675 676;; Append to "/tmp/tmp.txt" 677(define out-port (open-output-file "/tmp/tmp.txt" 678 #:exists 'append)) 679(displayln "Hola mundo" out-port) 680(close-output-port out-port) 681 682;; Read from the file again 683(define in-port (open-input-file "/tmp/tmp.txt")) 684(displayln (read-line in-port)) 685; => "Hello World" 686(displayln (read-line in-port)) 687; => "Hola mundo" 688(close-input-port in-port) 689 690;; Alternatively, with call-with-output-file you don't need to explicitly 691;; close the file 692(call-with-output-file "/tmp/tmp.txt" 693 #:exists 'update ; Rewrite the content 694 (λ (out-port) 695 (displayln "World Hello!" out-port))) 696 697;; And call-with-input-file does the same thing for input 698(call-with-input-file "/tmp/tmp.txt" 699 (λ (in-port) 700 (displayln (read-line in-port))))

Further Reading

Still up for more? Try Getting Started with Racket