Language Selection Criteria:
Influences on Language Design: computer architecture. Von Neumann architecture - influenced imperative programming languages
Language Categories: imperative, visual, scripting, logic, markup (not real programming language)
Implementation: compiled, interpreted, hybrid, preprocessors
Typing: Strong (java) vs weak (C); Static (java) vs dynamic (ruby)
Example of an Abstract Syntax Tree
How to remember each *fix from each other: the pre/in/post refer to the position of the operator; the child nodes always go left then right
Left child, Right child, then Operator (Postfix should not have brackets)
a b c + d e + f + - * foo g -
Operator, Left child, then Right child
(-(foo a (*(+ bc) (-(+ d e f ))))) g)
Left child, Operator, then Right child
Implements double-dispatch for a language that does not natively support it. Double dispatch is essentially calling a method that calls you back in an appropriate place.
Dynamically duck typed language designed for optimum programmer performance (possibly at the cost of software performance).
Roughly how it works: When passing a numeric type variable, if the least significant bit is = 0, then ruby assumes it is an integer value, and extracts the value from the next 31 bits. If the LSB is = 1, then ruby assumes then entire number is the id of the object.
class Person include ToFile attr_accesor :name def initialize(name) @name = name end def to_s name end end
Ruby allows developers to add functionality to include centralized code functions into any class using the "include {module}" statement.
class MyFunctionEvaluator def visit(someItem) someItem.accept(self) end def visitItemTypeA(item) return item.field end def visitItemTypeB(item) return item.field end end class ItemTypeA def accept(visitor) visitor.visitItemTypeA(self) end end a = ItemTypeA.new() mfe = MyFunctionEvaluator.new() puts mfe.visit(a)
Scala features "traits" which are essentially like interfaces, but that come with implementations. Another way to look at it is that they provide similar functionality to multiple inheritence but without inheriting the baggage of an entire ancestry
sealed abstract class Tree case class Children(li:List[Tree]) = List() extends Tree case class Node(i:Integer)extends Tree // this tries to find the 'li' parameter of Children //(if someObject is type Children) val Children(x) = someObject // OR... someObject match { case Children(x) => println (x) case Node(x) => println(x) case x => List(x) // catch all }
Some discussion of combinators: functions that combine to make composite functions. Parsers often made up of these.
Examples from the lecture included a partial BASIC language implementation for a lunar lander, and a financial application (stocks, bonds, and so on)
Defining a function requires the syntax: let [functionname] [list of parameters] = [function_expression]. Eg:
> let sum x y = x + y
Function with helper (this seems to be incorrect):
> let f1 a = f1 f2 a where f2 x = x + x
The type of a function is composed of types like the function itself. The :t instruction in the interactive Haskell environment returns the type of a function in the form: [function]::[param1Type]->[param2Type]->[outputParamType]. It gets a little confusing with composite functions. Example:
> let simpleFunction p1 p2 p3 = p3(p1 + p2) > :t hs hs :: Num a => a -> a -> (a -> t) -> t
My interpretation is: hs, where a is a Num (to the left of => is a restriction on the type), is of type where p1 is type a, p2 is type a, and p3 maps type a to type t. The type after the last -> is the resultant type. Summary:
> let twice f x = f(f(x)) > :t twice twice :: (a -> a) a -> a
let myprodt x = (prod ((fst x) (snd x )))::Double
"hello " ++ "world"
Guard is like an if/else or case statement in a haskell function
factorial :: Integer -> Integer factorial x | x > 1 = x * factorial(x -1) | otherwise = 1
Fibonaci in linear time
fibNextPair::(Integer, Integer) -> (Integer, Integer) fibNextPair (x, y) = (y, x + y) fibNthPair 1 = (1, 1) fibNthPair n = fibNthPair(fibNthPair(n-1))
Zip takes two lists and turns them into a single list of tuples consisting of members of each list at the same index location
[1..3] -- gives [1, 2, 3] take 4 [1,5..100] -- [1,5,9,13] let x = [1,5..] -- infinite list -- pairs the elements: [(1,1),(2,2),(3,3),(4,4),(5,5)] take 5 (zip x x) -- [(1,6),(2,7),(3,8),(4,9),(5,10)] take 5 (zip x (drop 5 x))
map: applies a function to every element of a list, returns the affected list
let x = [1,3..] let sqr x = x * x take 10 (map sqr x) -- output: [1,4,9,16,25,36,49,64,81,100]
-- makes a type called Boolean that can have two values data Boolean = True | False data Suit = Spades | Hearts deriving (Show)
type Card = (Rank, Suit) type Hand = [Card]
Here is an example of pattern-matching in Haskell. Pattern matching is similar to overloading in an object-oriented language. There are multiple definitions for the same function signature:
maze2String :: Bool -> [Wall] -> String maze2String horiz (Horizontal (row,0):rest) = "\n"++maze2String True rest maze2String horiz (Vertical (row,0):rest) = "\n| "++maze2String False rest maze2String horiz (NoWall (row,0):rest) = "\n "++maze2String False rest maze2String horiz (Horizontal (row,col):rest) = "+-"++maze2String True rest maze2String horiz (Vertical (row,col):rest) = "| "++maze2String False rest maze2String True (NoWall (row,col):rest) = "+ "++maze2String True rest maze2String False (NoWall (row,col):rest) = " "++maze2String False rest maze2String horiz []= ""
Getting started: http://clojure.org/getting_started
(+ 1 2 3 (* 2 2)) (< 1 2 3 4 5) (if nil nil "nil is false") (if false nil "false is false") (if 0 nil "everything else is true") (1 2 3) (list 1 2 3) '(1 2 3) ;Zfirst last rest cons nth [1 2 3 4]; - can apply as functions to index #{1 3 4 2} ; - sets {1 1, 2 4, 3 9, 4 16}; - maps - commas optional ; keywords - like symbols: {:foo 1, :bar 4, :brillig 9, :tove 16}
(def four (+ 3 1)) (defn funname "doc string" [param list] (+ param list)) (defn abc [a [_ b] [[c _ d]]] [a b c d]) (let [[_ a] value] (+ a 1)) (let [{name :name} value] (list name)) ; two forms of anonymous functions: (fn [params] (list params)) #(list (+ 1 (count %)))
(defprotocol Compass (defrecord SimpleCompass
(def aref (ref "value")) @aref (dosync (alter aref str "update")) (def val (atom "old")) @val (reset! val "new") (swap! val fun "update") (def bond (agent 1)) @bond (send bond double) (def iNeed (future (Thread/sleep 10000) "a result")) @iNeed
(map count '((1 2 3) [4 5 6] #{7 8 9} {10 11 12 13}) (apply + [1 2 3 4]) (filter odd? #{1 2 3 4}) (every? odd? '(1 2 3)) (some odd? '(1 2 3)) (not-every? odd? '(1 2 3)) (not-any? odd? '(1 2 3)) (for [x seq1, y seq2] (list x y)) (for [x seq1, y seq2, :when (<= x y)] (list x y)) (reduce + '(1 2 3)) (sort '(4 -1 2 -3)) (sort-by abs '(4 -1 2 -3))
(defn mycount [v] (if (empty? v) 0 (inc (mycount (rest v))))) (loop [v] (if (empty? v) 0 (inc (size (rest v))))) (defn mycount2 [v] (loop [v v, c 0] (if (empty? v) c (recur (rest v) (inc c))))) (repeat 4) (cycle '(1 2 3)) (take 4 (cycle '(1 2 3))) (drop 2 (take 4 (cycle '(1 2 3))))
user > (defn twice-count [w] (* 2 (count w))) #'user/twice-count user > (twice-count "Lando") 10 user > (map twice-count people) (6 16) ; anonymous version user > (map (fn [w] (* 2 (count w))) people) (6 16) ; alternate anonymous version user > (map #(* 2 (count %)) people) (6 16)
From here:
; async Agent: (def agent_variable (agent 1)) @some_agent (send agent_variable double) ; a future from the book (def future_handler (future (Thread/sleep 5000) "take time"))
Designed by phone company for highly reliable software. Functional paradigm.
erl
allows interactivity2 + 2. 2 < 4.0. symbol Variable % must begin with uppercase char = % is pattern-match/binding - once [[3,4],5,6]. [3,4|[5,6]]. % can have improper lists {2,3,4}. {valid,[H|T],X} = {valid,[1,2,3],blat}.
c(matching_function). %- can apply as functions to index matching_function:number(one). c(yet_again). Negate = fun(X) -> -X end.
lists:foldl(fun(X, Sum) -> X + Sum end, 0, Numbers). lists:map(fun(X) -> X + 1 end, Numbers). lists:filter(Small, Numbers). lists:all(Small, [0, 1, 2]). lists:any(Small, Numbers). lists:takewhile(Small, Numbers). lists:dropwhile(Small, Numbers). lists:foldl(fun(X, Sum) -> X + Sum end, 0, Numbers). % list comprehensions: % generators and filters: [{X,Y}||X <-[1,2,3,4],X < 3,Y<-[5,6],Y<=X].
receive Pattern -> ...; Pattern -> end Pid = spawn(fun abcdef) Pid = spawn(module,fun,[args]) Pid ! message link(Pid) % leads to {'EXIT', From, Reason} Pid = spawn_link(fun abcdef) register(atom,Pid) self()
Language | Typing | Paradigm(s) | Notes |
---|---|---|---|
Ruby | Dynamic (duck) | Object Oriented | Designed for programmer efficiency |
Scala | Static | Object Oriented with Functional subset | Partial hybrid of OO and functional |
Haskell | Static | Pure Functional, stateful with the use of Monads | Lazy evaluation |
Clojure | Dynamic (duck) | Functional with imperative subset | Lisp-based language with lazy evaluation |
Erlang | Dynamic | Functional, mostly immutable | Prolog-like syntax; excellent concurrency support |