Home [Clojure] Do Things: A Clojure Crash Course - Syntax
Post
Cancel
Preview Image

[Clojure] Do Things: A Clojure Crash Course - Syntax

Clojure의 syntax는 간단하다. Lisp과 같다고 한다.

그런데 나는 Lisp도 모르는데?

검색하다보니, https://learnxinyminutes.com/docs/ko-kr/clojure-kr/ 링크에서 쉽게 공부할 수 있어서 남겨본다.

그런데 이걸 보니… 대충 다 알게 된 것 같다.

우선 기본적인 문법은 그냥 따라가보면서 익혀보겠다.

Forms

모든 Clojure 코드는 동일한 구조로 작성되어 있으며, 두 종류의 구조로 인식한다.

  • 데이터 구조의 리터럴 표현(숫자, 문자열, 지도, 벡터 등)
  • 연산들

우리는 유효한 코드를 나타내기 위해 폼(form)이라는 용어를 사용한다.

또 Clojure forms을 나타내기 위해 expression이라는 용어도 가끔 나온다.

아래는 모두 유효한 폼들이다.

1
2
3
4
5
6
learning-clojure.core=> 1
1
learning-clojure.core=> "a string"
"a string"
learning-clojure.core=> ["a" "vector" "of" "strings"]
["a" "vector" "of" "strings"]

연산은 다음과 같은 구조를 띄고 있다.

1
(operator operand1 operand2 ... operandn)

comma(,)가 없다는 것에 유의하자.

Clojure는 operands 를 나눌 때 whitespace를 사용한다.

1
2
3
4
learning-clojure.core=> (+ 1 2 3)
6
learning-clojure.core=> (str "It was the panda " "in the library " "with a dust buster")
"It was the panda in the library with a dust buster"

Control Flow

if, do, when이 있다.

if

if 의 구조는 다음과 같다.

1
2
3
(if boolean-form
  then-form
  optional-else-form)

if 옆에 조건을, 바로 아랫 줄에는 true일때, 그 다음 줄에는 false일 때를 적어주면 된다.

1
2
3
4
5
6
7
8
learning-clojure.core=> (if true
                   #_=>   "By Zeus's hammer!"
                   #_=>   "By Aquaman's trident!")
"By Zeus's hammer!"
learning-clojure.core=> (if false
                   #_=>   "By Zeus's hammer!"
                   #_=>   "By Aquaman's trident!")
"By Aquaman's trident!"

else 브랜치를 뺄 수도 있다. 이 경우 Clojure는 nil을 리턴한다.

1
2
3
learning-clojure.core=> (if false
                   #_=>   "By Odin's Elbow!")
nil

do

do 는 여러 폼들을 묶어서 각각 실행하게 해준다.

1
2
3
4
5
6
7
learning-clojure.core=> (if true
                   #_=>   (do (println "Success!")
                   #_=>       "By Zeus's hammer!")
                   #_=>   (do (println "Failure!")
                   #_=>       "By Aquaman's trident!"))
Success!
"By Zeus's hammer!"

대충 설명하자면, Success! 를 출력 후, "By Zeus's hammer!" 을 리턴한 것이다.

when

whenifdo 의 조합같은 것이지만, else 브랜치는 없다.

1
2
3
4
5
learning-clojure.core=> (when true
                   #_=>   (println "Success!")
                   #_=>   "abra cadabra")
Success!
"abra cadabra"

음… 뭔가 맛이 없다. 알 듯 모를 듯 하다. 다른 예시를 보자.

ClojureDocs에 가보니 다음과 같이 써있다.

https://clojuredocs.org/clojure.core/when

(when test & body)

Evaluates test. If logical true, evaluates body in an implicit do.

정말, true이면 실행해주는게 전부이다.

1
2
3
4
learning-clojure.core=> (when false
                   #_=>   (println "Success!")
                   #_=>   "abra cadabra")
nil

그래서 false를 넣어주면 nil을 리턴하고 마친다.

whenifdo 의 조합이다.

nil, true, false, Truthiness, Equality, and Boolean Expressions

Clojure은 true, false 값들을 가진다.

nil 은 Clojure에서 값이 없음을 나타낼 때 사용된다.

value의 값이 nil인지 확인하려면, nil? 이라는 함수를 사용하면 된다.

1
2
3
4
learning-clojure.core=> (nil? 1)
false
learning-clojure.core=> (nil? nil)
true

nilfalse는 모두 논리적으로 거짓을 나타내지만, 나머지 값들은 모두 논리적 참이다.

참과 거짓은 if 에서의 첫 expression과 같이 Boolean expression에서 값을 다룰 때 사용된다.

1
2
3
4
5
6
7
learning-clojure.core=> (if "bears eat beets"
                   #_=>   "bears beets Battlestar Galactica")
"bears beets Battlestar Galactica"
learning-clojure.core=> (if nil
                   #_=>   "This won't be the result because nil is falsey"
                   #_=>   "nil is falsey")
"nil is falsey"

Clojure에서 동등 연산은 = 이다.

1
2
3
4
5
6
learning-clojure.core=> (= 1 1)
true
learning-clojure.core=> (= nil nil)
true
learning-clojure.core=> (= 1 2)
false

or and and

or 은 첫 번째 truthy 값이나 마지막 값을 반환한다.

and 는 첫 번째 falsey 값이나 어떤 값도 falsey가 아니라면 마지막 truthy 값을 반환한다.

1
2
3
4
5
6
learning-clojure.core=> (or false nil :large_I_mean_venti :why_cant_I_just_say_large)
:large_I_mean_venti
learning-clojure.core=> (or (= 0 1) (= "yes" "no"))
false
learning-clojure.core=> (or nil)
nil
1
2
3
4
learning-clojure.core=> (and :free_wifi :hot_coffee)
:hot_coffee
learning-clojure.core=> (and :feelin_super_cool nil false)
nil

Naming Values with def

def 는 이름과 값을 묶어준다.

1
2
3
4
5
learning-clojure.core=> (def failed-protagonist-names
                   #_=>   ["Larry Potter" "Doreen the Explorer" "The Incredible Bulk"])
#'learning-clojure.core/failed-protagonist-names
learning-clojure.core=> failed-protagonist-names
["Larry Potter" "Doreen the Explorer" "The Incredible Bulk"]

그런데 여러 값을 하나의 이름에 붙이고 싶다면 어떻게 할까?

만약 루비라면 다음과 같이 작성했을 때처럼 말이다.

1
2
3
4
5
6
7
severity = :mild
error_message = "OH GOD! IT'S A DISASTER! WE'RE "
if severity == :mild
  error_message = error_message + "MILDLY INCONVENIENCED!"
else
  error_message = error_message + "DOOOOOOOMED!"
end

error_message 값을 if 문에 따라 확장하게 된다.

이걸 Clojure로 작성하려면 어떻게 할까?

1
2
3
4
5
6
; 틀린 예시다.
(def severity :mild)
(def error-message "OH GOD! IT'S A DISASTER! WE'RE ")
(if (= severity :mild)
  (def error-message (str error-message "MILDLY INCONVENIENCED!"))
  (def error-message (str error-message "DOOOOOOOMED!")))

이런 식으로 쓸 수 있지만, 이건 틀린 예시다.

name과 value에 대해서 좀 더 자세히 알면 이해할 수 있지만, 다음과 같이 작성하면 된다.

1
2
3
4
5
6
7
8
9
10
11
learning-clojure.core=> (defn error-message
                   #_=>   [severity]
                   #_=>   (str "OH GOD! IT'S A DISASTER! WE'RE "
                   #_=>        (if (= severity :mild)
                   #_=>          "MILDLY INCONVENIENCED!"
                   #_=>          "DOOOOOOOMED!")))
#'learning-clojure.core/error-message
learning-clojure.core=> (error-message :mild)
"OH GOD! IT'S A DISASTER! WE'RE MILDLY INCONVENIENCED!"
learning-clojure.core=> (error-message :not-mild)
"OH GOD! IT'S A DISASTER! WE'RE DOOOOOOOMED!"

대충 느낌이 오다시피, 함수를 선언하고 하나의 변수를 받게끔 한다음 할당하게 처리해준다.

나중에 다시 설명해준다고 한다.

References

This post is licensed under CC BY 4.0 by the author.

[Clojure] Do Things: A Clojure Crash Course

[Clojure] Do Things: A Clojure Crash Course - Data Structures