;; 참조:
;; http://pupeno.com/2011/08/16/why-i-love-lisp/
; 2015-02-13 23:44:49 (금요일)
; 2015-02-14 14:31:10 (토요일)
; 클로저를 배워보자.
; 이것이 주석이다.
;; 이것이 주석이다.
( comment
이것이 여러줄 주석이다.
Hello World.
한글좀 써보자.
)
;; 헬로월드다.
( println "Hello World." )
;; 괄호위치가 심상치 않다.
;; 대부분 언어에서 괄호위치는 함수명 뒤에 오지않나?
;; println( "Hello World.")
;; 한글좀 써보자.
(println "안녕하신가.")
;; 1 더하기 2.
(+ 1 2)
;; 아. 연산자의 위치가 앞에 나와있는데.
;; 대부분 언어에서 연산자 위치는 중간에 있지않나?
;; (1 + 2)
( comment
용어 정의 한번 하고 가자.
클로저에서 "쿠오트", "백틱"이 자주쓰인다.
자주쓰이면서, 유의미하게 쓰인다.
;; ' : quote
;; ` : back-tick
)
;; symbol
'aaaa
'한글
;; vector
[1 2 3 4]
;; list
'( a b c d )
;; nested list
'( a ( b c ) d )
;;
;; 심볼을 쓸때 ' 를 해주지 않으면 에러가난다.
;; 심볼의 값을 평가하기때문이다.
;; ' 를 써주면, 값을 평가하지 말라는 뜻이다.
;;
;; 변수정의
( def hello-world "Hello World!!!" )
;; 변수사용
( println hello-world )
;; 변수정의할때, def 를 쓴다는점.
;; 변수정의할때, - 도 사용가능하다는점.
;; 함수
(fn [n] (* n 2))
;; 이 함수는 이름이 없다.
;; 이름없는 함수에 이름을 붙여주자.
(def twice (fn [n] (* n 2)))
;; 함수를 불러보자.
(println (twice 10))
;; 한글변수를 시험해보자.
( def 한글변수 "안녕하쇼~")
( println 한글변수 )
;; 한글함수를 시험해보자.
( def 따블 (fn [숫자] (* 숫자 2)))
( println (따블 20))
;; 이름없는 함수를 정의하고, 이름을 붙이는데,
;; 두개의 키워드(def, fn) 가 사용된다.
;; 이것을 하나의 키워드로 편하게하자.
(defn twice [n] (* 2 n))
(println (twice 32))
;; if 문을 써보자.
(defn twice [n] (if (> n 50) 100 (* n 2)))
(println (twice 45))
;;
;; 괄호가 전체 문장을 감싸고 있어서,
;; 문장이 마치, list 또는 nested list 처럼 보인다는 점.
;; 연산자가 맨앞에 나와있다는점.
;; if 문에서도 비교연사자가 맨앞에 나와있다!
;;
;; 함수를 줄바꿈으로 이쁘게 써보자.
(defn twice [n]
(if (> n 50)
100
(* n 2)))
(println (twice 33))
;; 새로운 문법을 만든다고 해보자.
;; 연산자가 뒤에 나오는 문법을 만든다고해보자.
;; 현재 클로저에서 다음과 같이 쓰면,
;; 에러가 난다.
;;(4 5 +)
;; java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn
;; 위 에러를 해결하기위해
;; 다음과 같은 함수 하나를 고안한다.
(defn psil [exp]
(reverse exp))
;;(psil (4 5 +))
;; 이것도 에러가난다. 원인은,
;; psil 이 실행되기전에 (4 5 +) 를 평가하기 때문이다.
;; (4 5 +) 를 list 로 만들어주면, 평가하지 않는다.
(psil '(4 5 +))
(println (psil '(4 5 +)))
;; ( + 5 4)
;; 이것은 실행은 되지만,
;; 내가 원하던값 9 는 아니다.
;; 값이 평가되지 않았다.
;; 평가를 하도록해주자.
(eval (psil '(4 5 +)))
(println (eval (psil '(4 5 +))))
;; 이것은 잘 실행되고, 평가도 된다.
;; 원하는 값 9 가 나왔다.
(eval (psil '(4 5 +)))
;; 코드를 다시보자.
;; 모양이 nested list 다.
;; "중첩된 리스트" 모양이다.
;; '(4 5 +)
;; 이것은 데이터이다. 리스트다.
;; 위코드는 리스트를 실행시키는 코드다.
;; 위코드는 데이터를 실행시키는 코드다.
;; 데이터가 코드가 되는 순간이다.
;;
;; 그토록 바라던것.
;; 데이터가 코드가되고, 코드가 데이터가 되는것.
;;
;; 마치,
;; 에너지와 질량이 상호 변환가능(E=mc^2)한 것처럼.
;; 코드와 데이터가 상호 변환가능하다는 사실(Code <=> Data) 이
;; 관찰되는 순간이다.
;; 코드는 데이터가 되고, 데이터는 코드가 된다.
;;
; 나는 이것을
;; "데이터로, 실행되는 프로그램을 만들수있다"는 의미로 해석한다.
;;
;; 평가되지않는 인자를 받아서,
;; 평가된 결과를 내는 기능을 매크로(Macro)라고 한다.
(defmacro psil [exp]
(reverse exp))
(psil (4 5 +))
(println (psil (4 5 +)))
;; (println (psil (4 5 +)))
;; (println (eval (psil '(4 5 +))))
;;
;; 위 코드를 비교해보자.
;; 매크로를 쓰면, eval 을 쓰지 않아도 된다.
;; 매크로를 쓰면, quote (') 를 쓰지 않아도 된다.
;; 어마어마한, 도약이다.
;;
;; Clojure 문법에 맞지않는 문장 "(4 5 +)" 이 어째서 에러가 나지않는가.
;; 그것은 psil 이 실행되기 전까지는 데이터가 평가되지 않기때문이다.
;; 데이터를 요리해서 다른 프로그램을 만들어낼수있는것이다.
;; 이 기능은 나만의 프로그래밍 언어를 만드는것을 가능하게 해준다.
;; Lisp 언어에서 내가 필요한 어떤 문법이라도 쓸수있게 해준다.
;; 이것이, 개발자가 원하는 궁극의 그무엇이 아닌가.
;; 새로운 문법을 만들수 있다면,
;; 이것이 바로 요즘 유행하는 DSL 이 아닌가.
;; 매크로를 평가하지는 않고, 데이터가 처리된 결과만을
;; 돌려주는 연산자가 있다. macroexpand 이다.
;; 이것으로 평가하려는 코드를 볼수있다.
(macroexpand '(psil (4 3 +)))
(println (macroexpand '(psil (4 3 +))))
;; 매크로는 컴파일타임에 실행되는 함수로 생각하면된다.
;; Lisp 에서는 컴파일타임과 런타임이 섞여있다.
;; 이 둘사이를 계속 왔다갔다 할수있다.
;; do 연산자를 한번보자.
(do (println "Hello") (println "World"))
;; do 는 평가식을 하나씩, 순차적으로 실행한다.
;; do 에 넘겨진 여러개 평가식은
;; 전체가 하나의 평가식으로 그룹지어진다.
;; 매크로를 만들때, do 를 써보자.
(defmacro psil [exp]
(println "compile time")
`(do (println "run time")
~(reverse exp)))
;; back-tick(`) 은 quote(') 와 기능이 같다.
;; 값을 평가하지 말라는 뜻이다.
;; back-tick 에서 tilde (~) 가 나오면
;; tilde 가 사용된 곳에서는 다시 평가하라는 뜻이다.
;; 즉, 평가식중에서 특정 일부분을
;; 평가할것인지 말것인지를 켰다 껐다 할수있는 기능이다.
;; tilde(~) 는 quote(') 에서 쓰면 에러가 난다.
;; tilde(~) 는 back-tick(`) 과 같이 써야, 에러가 안난다.
(psil (4 5 +))
(println (psil (4 5 +)))
(println (macroexpand '(psil (4 5 +))))
(comment
;; cond 를 한번 보자.
(cond (= x 0) "영이다."
(= x 1) "일이다."
:else "다른거다.")
;; cond 는 다른언어에서
;; switch 문 이나 case 문 처럼 생겼다.
;;
)
;; 다음 예제는 if 문도 만들수 있다는것을
;; 보여주는 예제인데, 예제가 깔끔하지 않다.
;; 의미를 명확하게 보여주지 못한다.
;;
;; 언어의 일부분인 if 문까지도 매크로를 통해서
;; 만들수 있다는 것을 보여주려는 의도이다.
;; 그런데 사용한 cond 예제코드가
;; 최적의 선택은 아닌것으로 생각된다.
;; my-if 를 함수로 만들면 부작용이 발생한다.
(defn my-if [predicate if-true if-false]
(cond predicate if-true
:else if-false))
(my-if (= 0 0) "equals" "not-equals")
(println (my-if (= 0 0) "equals" "not-equals"))
(my-if (= 0 1) "equals" "not-equals")
(println (my-if (= 0 1) "equals" "not-equals"))
(println "-------------------")
(my-if (= 0 0) (println "equals") (println "not-equals"))
;; 이 부작용을 매크로가 해결해준다.
(defmacro my-if [predicate if-true if-false]
`(cond ~predicate ~if-true
:else ~if-false))
(println "#-------------------")
(my-if (= 0 0) (println "equals") (println "not-equals"))
(my-if (= 0 1) (println "equals") (println "not-equals"))
(println (= 0 0))
(println (= 0 1))
(println (macroexpand '(my-if (= 0 0) (println "equals") (println "not-equals"))))
(println (macroexpand '(my-if (= 0 1) (println "equals") (println "not-equals"))))
|
---|
2015년 2월 13일 금요일
Clojure 연습 1
Firefly Algorithms
firefly algorithm 001 Firefly Algorithms ¶ 반딧불 알고리즘 번역 요약 ¶ References [1] X. S. Y...
-
// 그루비를 배워보자. /* 주석이 되나. */ // 그래. 이것이 그루비 코드다. // 2015-02-12 11:34:45 (목요일) println( "Hello world" ) printl...
-
firefly algorithm 001 Firefly Algorithms ¶ 반딧불 알고리즘 번역 요약 ¶ References [1] X. S. Y...
-
;; 참조: ;; http://pupeno.com/2011/08/16/why-i-love-lisp/ ; 2015-02-13 23:44:49 (금요일) ; 2015-02-14 14:31:10 (토요일) ; 클로저를 배워보자...