Skip to content

Instantly share code, notes, and snippets.

Created September 5, 2014 15:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/dc38b3ce7e971bd42f13 to your computer and use it in GitHub Desktop.
Save anonymous/dc38b3ce7e971bd42f13 to your computer and use it in GitHub Desktop.
#lang racket
;; hello world in Racket
;; comments begin with ;
;; some people like to use ;;
;; function application is done by surrounding the function name and arguments in parens
;;
;; if you have seen languages like Python or JavaScript, f(a,b,c) is (f a b c) in scheme
(displayln "Hello, world!")
;; displayln can display pretty much anything we give it, not just strings
(displayln
(+ 2 (* 4 5))) ;; 2 + 4 * 5
(displayln displayln) ;; displays something saying it is a procedure and the name of that
;; btw, scheme uses the word "procedure" not "function" usually
;; as you might've figured out we can do things with procedures that we would normally do with other values like numbers and strings
;; procedures are values in Scheme
(displayln
'(1 2 3 4)) ;; two things to note, scheme doesn't generally care about indentation or anything
;; '(1 2 3 4) is a quoted list of number literals
(displayln
(equal? '(1 2 3 4)
(cons 1 (cons 2 (cons 3 (cons 4 '())))))) ;; returns #t which indicates it is true, they are equal
;; quoting
;; when we put the ' character in front of things that means we are quoting them
;; this is actually a special notation for a more regular form
(displayln
(equal? (quote (1 2 3 4))
(cons 1 (cons 2 (cons 3 (cons 4 '()))))))
;; (quote blah) = 'blah
;; other literals can be quoted
'a ;; we call this a symbol
'3 ;; this is actually the same as 3, numbers are automatically quoted for you
'"abc" ;; same with strings, equal to "abc"
''3 ;; we are actually quoting '3 so it does not become a number, remember 'a = (quote a), ''a = (quote (quote a))
;; the symbol quote is special so if we wanted '(quote 4) we would do
'('quote 4) ;; makes quote not get transformed
;; what are lists actually?
(cons 1 2) ;; "improper" list, it is not a list unless the last element is '(), cons actually creates pairs
(cons 1 (cons 2 '()))
;; list accessors
(equal? (car '(1 2 3))
1)
(equal? (cdr '(1 2 3))
'(2 3))
;; definitions
;; we can use the define form to give names to data
;; this is similar to initialization if you are familiar with that
(define x 4)
(define xs '(1 2 3 4))
;; procedures
;; the way you create procedures in scheme is with lambda
(lambda (x y) (+ x (* y y)))
;; we can give them names since they are data as well
(define plusmult (lambda (x y) (+ x (* y y))))
(plusmult 2 3)
;; scheme gives us a special form that gets transformed to the above
(define (plusmult2 x y)
(+ x (* y y)))
;; the two are equivalent, and in fact most schemes will internally transform it to the above
;; notice we do not require a return keyword, scheme procedures just return whatever the body is, which is always some kind of expression
;; variable binding
;; when we do (lambda (x) body-here) we are actually creating a binding for x in the body of the function
;; this means that when we call the function later, with (f 4) say, then x gets bound to 4 in the body of f
;; this can be leveraged to do things that in other languages require extra work and special cases
((lambda (x) (+ x x)) 2)
;; scheme gives us notation for this as well, which also gets translated internally to something simpler
(let ((x 2))
(+ x x))
(let ((x 4) ;; notice this does not shadow the previous binding
(y 5))
(+ x y))
;; if we wanted to refer to other bindings when giving them values we use let*
(let* ((x 4)
(y (+ x x)))
(+ x y))
;; there are many other variations of let, but I will leave it at these two for now and let you discover more later
;; conditionals
(if #t "true" "false")
(cond
((equal? 3 3) "blah")
(else "blargh"))
;; recursion
;; see: recursion
(define (factorial n)
(if (equal? n 0) 1 ;; base case = 1
(* n (factorial (sub1 n))))) ;; inductive/recursive case
(factorial 5)
;; lists are useful combined with recursion
(define (sumlist xs)
(cond
((empty? xs) 0)
(else (+ (car xs)
(sumlist (cdr xs))))))
(sumlist '(1 2 3 4 5))
(define (prodlist xs)
(cond
((empty? xs) 1)
(else (* (car xs)
(prodlist (cdr xs))))))
(prodlist '(1 2 3 4 5))
;; notice how these things have something in common? :)
;; they're both of the form
;; check if list is empty
;; if yes, return some value
;; otherwise combine the first value in the list with a recursive call to the rest of the list
;; scheme abstracts this into a procedure called foldr
;; foldr takes a combining procedure, an "identity" value, and a list of values to be combined
;; the order does not matter here but, just so you know, the current running total is passed as the first argument to the combiner and the current value is the second argument
(define (sumlist2 xs)
(foldr + 0 xs))
(define (prodlist2 xs)
(foldr * 1 xs))
(equal?
(sumlist2 '(1 2 3 4 5))
(sumlist '(1 2 3 4 5)))
(equal?
(prodlist2 '(1 2 3 4 5))
(prodlist '(1 2 3 4 5)))
;; we can also define factorial in terms of prodlist
(define (factorial2 n)
(prodlist2 (range 1 (add1 n))))
(factorial2 6)
;; scheme also has other useful procedures like this
(map (lambda (x) (+ 1 x)) '(1 2 3 4 5))
(filter (lambda (x) (not (equal? x 2))) '(1 2 4 2 4 5))
;; these are called higher-order procedures
;; this fancy term simply means that they take procedures as one or more of their arguments and/or return procedures
;; we haven't seen any that return procedures yet though, so let's see
((compose
add1
(lambda (x) (* 2 x)))
3)
;; that probably seemed strange!
;; compose takes procedures and essentially creates "pipelines" between them
;; function composition is actually just f(g(x)) using math notation
;; so taking the output of one proc and providing it as the argument to another, and finally returning the output of that
;; compose gives us a new proc that does this
;; if you have seen compose before prepare to be amazed, scheme can compose procedures that expect more than one argument!
((compose
+
(lambda (x y)
(values (add1 x) (add1 y)))) ;; the "values" form is required to return multiple values, which the next procedure, +, expects
2 5)
;; if you just have procedures of one argument it is best to use compose1 which is specially for those and is more efficient
;; pattern matching!
(define (factorial3 n)
(match n
[0 1]
[n (* n (factorial (sub1 n)))]))
;; yet another way of defining factorial
(define (factorial4 n) (apply * (range 1 (add1 n))))
;; btw, (range 1 1) = '(), but that still returns 1 if you do (factorial4 1)
;; because in Scheme (*) = 1, and (+) = 0
(factorial3 6)
;; pattern matching lets us do cool logic-ish things which would be
;; tedious in imperative languages like Python or Java
(define (occurs? v e)
(match e
[(list 'var v2) (equal? v v2)]
[(list 'add l r)
(ormap (curry occurs? v) (list l r))]
[(list 'mul l r)
(ormap (curry occurs? v) (list l r))]))
(occurs? 'y '(add (add (var v) (var t)) (var y)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment