|
Lisp is a functional programming language, which basically means that ideally only function return values and no explicit symbols (aka variables) are used. However, sometimes it is necessary or convenient to use a symbol. A symbol's type is that of its data (compared to procedural languages, such as C, which have explicit variable types (i.e. char, int, float)) This means that symbols can store anything, from atoms and lists to functions and whole programs, which are really just big lists.
Everything is lisp is either an atom or a list (technically called an S-expression).
- Atoms are single values, such as 'A, 'dog, "Hello world", etc. (The ' tells lisp not to interpret what follows it right away
- Lists are composed of atoms, symbols (the term for lisp's "variables") or be the empty list (represented either as () or NIL)
Example lists:
(4 3 4) ;;; list of numbers
(A B C) ;;; list of symbols
(A B (C (D E)) F (G)) ;;; list with nested lists
('cat 'dog "African elephant") ;;; list of atoms
Since lisp is interpreted, we can interactively execute a function or snippet of code.
Simple mathematical functions, such as +,-,/,*, etc can be done as follows:
(+ 1 1) ;;; returns 2
(* 2 3) ;;; returns 6
(- 20 (* 3 4)) ;;; returns 8
etc.
Similarly, functions can be called using the same syntax. For example,
(function-name param1 param2) would call function-name with parameters param1 and param2
We define functions using the keyword "defun".
;;;a factorial function
(defun factorial (n)
(if (= n 0) 1 ;;; return 1
(* n (fact (- n 1))) )) ;;; else return factorial(n-1)
In the factorial example, 1 is returned when n equals zero, otherwise we return the factorial of the rest of the numbers. In fact, for any function, the last statement executed is returned by default. However, we can override what is being returned by using the "return" keyword in place of what would be returned. On a side note, lists are terminated by matching the parens enclosing the statement.
We can set symbols using the "setf" macro. For example,
(setf alpha '(1 2 3)) ;;; sets the symbol "alpha" to the list (1 2 3)
(setf result sqrt(4)) ;;; sets the symbol "result" to 2
Lisp has several core functions that allow for some basic manipulations on lists.
List -- creates a list from a series of atoms
(list 'a 'b 'c) ;;; returns (a b c)
(first '(a b c)) ;;; returns a, the first symbol in the list
(rest '(a b c)) ;;; returns (b c), everything after the first symbol
(last '(a b c)) ;;; returns (c), the very last symbol
(first (rest '(a b c))) ;;; returns b
(reverse '(a b c)) ;;; returns (b c a)
(append '(a b c) '(d)) ;;; returns (a b c d)
(apply '+ '(1 2 3)) ;;; returns 6; apply uses the function + on all the elements
(mapcar #'1+ '(1 2 3)) ;;; returns (2 3 4); uses the add-one function on each element
So, there's a brief overview of what lisp is and simple things that can be done with it.
Sample Usage
For kicks, here's my 1st-place winning agent that plays the game "election", just so you can see a pseudo-real-world example of it being used. Hopefully it'll make sense without describing everything.
The agent is told how many votes it gets and it returns a ballot (aka list) of its voting record.
If you call it as such:
(AgentRndHigh 10 6)
It might return:
(0 1 0 2 4 3) ;;; 6 position, 10 votes total
-----------------------------------------------------------------------
;;; AgentRndHigh
;;; Plays random numbers towards the upper range of [max_value/2,max_value]
;;; the max_value is a constant, which is 5*num_players possible scoring "columns"
;;; the num_votes is how many votes we get for this round
(defun AgentRndHigh( num_votes max_value )
(setf ballot (Repeat 0 max_value)) ;;; generate a ballot of 0s (0 0 0...0)
(dotimes (i num_votes)
(setf pos (+(/ max_value 2)(random (/ max_value 2))))
;; add a vote for a random position
(setf (nth pos ballot) (1+ (nth pos ballot))))
(return ballot)
)
|