clojure – 네임스페이스안에 정의되어 있는 함수 보기

클로저 개발을 하다 보면, 네임스페이스 안에 정의되어 있는 함수들을 보고 싶을 때가 있다.

LightTable이 아닌 autocomplete가 제공되지 않는 IDE에서 개발을 할때면, 아.. 뭐지? 공욕을 치룰때가 있다.

그럼 어떻게 네임스페이스안의 함수들을 볼 수 있을지 알아 보자.

1. keys 함수를 이용하여, 함수 시퀀스 반환하기.

user=> (keys (ns-publics 'foo))

그 외 ns- 많은 함수들을 제공하니 찾아서 실험해보도록 하자.

2. dir 함수를 이용하기. dir함수는 clojure.repl에 선언되어 있는 함수이다.

user=> (require 'clojure.repl)
user=> (clojure.repl/dir 'foo)

그 외 다른 방법도 있으나, 위 두가지 방법이 제일 괜찮은거 같다.

이상.

Clojure – Clojure Cider REPL에서 쓰래드를 사용하였을 때 print 되지 않는 이유와 해결 방법

참고 링크

Q> Emacs Cider REPL에서 백그라운드 쓰레드에서 println을 돌렸을 때 왜 출력이 되지 않는가?

A> 원인은 출력되는 버퍼가 다르기 때문이다.

println의 행동은 동적으로 *out* 라는 output stream에 바인딩 되어 출력되는데, 만약 thread를 사용한다면, 그 thread는 루트 *out* 에 바인딩 될것이고, 그렇게 되면 사용하고 있는 REPL에서는 확인을 할 수 없다.

그러면 어디서 확인할 수 있는가?

buffer list에서 *nrepl-server*라는 이름을 가진 버퍼에서 확인 할 수 있다.

또는

(alter-var-root #'*out* (constantly *out*))

와 같이 바꾸어 기존 buffer에서 확인 할 수 있다.

참고 링크

만약 Cider REPL을 사용하지 않는다면, nrepl을 시작한 터미널에서 확인 할 수 있다.

Clojure – ` syntax-quote와 ‘ quote의 차이점에 대해서

`syntax-quote와 'quote의 차이점에 대해서 알아보자.

첫번 째 syntax-quote는 namespace를 반환한다.
user>'x
x

user>`x
user/x

두번 째 syntax-quote는 ~unquote 또는 ~@unquote splicing 매크로를 사용할 수 있다.

user> `(this ~(symbol (str "i" "s" - "cool")))
(user/this is-cool)

user> '(this ~(symbol (str "i" "s" - "cool")))
(this (clojure.core/unquote (symbol (str "i" "s" - "cool"))))

위와 같이 두가지 차이점을 알수 있었다. 더 자세한 내용은 아래의 링크를 통해서 확인 할 수 있다.

reference

Clojure – ` syntax quote에 대해서

`syntax quote에 대해서 알아보자.

`와 연관있는 ~ unquote, 그리고 ~@unquote splicing이 있다.

위 두가지는 syntax quote를 이용하였을 때 그 반대의 영향을 주기 위해서 사용된다.

심볼을 심볼 그 자체로 활용하기 위해 사용된다. 'quote와 비슷하면서도 다르다. sytax quote 설명은 다른 장에서 알아보자.


user> (def five 5)
user/five
user>`five
user/five

p>한가지 기억하자. Clojure에서 모든 것들이 데이터이다. 위와 같이 quote를 사용하였을 때 평가되지 않고 심볼 자체 또는 리스트 자체로 출력이 되는 것을 볼수 있다.

그럼 왜 quote가 필요할까? 한가지 더 실험을 해보자.

(1 2 3)
Unhandled java.lang.ClassCastException
java.lang.Long cannot be cast to clojure.lang.IFn

` 위와 같이 에러가 발생된다. 이유는 현재 1이라는 심볼이 정의 되어 있지 않기 때문에 발생된다. (, )에 둘러 쌓여있을 때 첫번 째 argument는 심볼로 인식된다.

다시 quote를 활용해보자.


user>`(1 2 3)
(1 2 3)

에러 없이 정상으로 작동된다.

다음 장에서 `syntax-quote와 '의 차이점에 대해서 알아보자.

reference

Clojure – ~@ unquote splicing macro에 대해서

~@ unquote splicing macro에 대해서
unquoute splicing macro에 대해서 이해하기 위해서는 먼저 unquote macro에 대해서 알아야한다.

unquote splicing macro는 ~@로 기록하도록 하겠다.

~@는 form에 있는 심볼들을 모두 평가하기 위해 사용된다.

예제를 통해서 이해해보도록 하자.


user> (def three-and-four (list 3 4))

'user/three-and-four

위와 같이 심볼을 하나 만들었다.

그리고 그저 ~unqoute 로만 평가를 했을 때

user> `(1 ~three-and-four)
(1 (3 4))

위와 같이 평가된다.

여기서 unqoute splicing macro를 이용하여 폼 안에 있는 모든 심볼을 평가하고 싶을 때 아래와 같이 사용할 수 있다.


user> `(1 ~@three-and-four)
(1 3 4)

이상으로 unqoute macro와 unquote splicing macro에 대해서 알아보았다.

Clojure – ~ (unqoute)에 대해서

~ unqoute 매크로. ~ 는 unqoute 라고 읽는다. unqoute를 이해하기 위해서는 ` (syntax quote)에 대해서 알아야한다. 그럼 일단 syntax sqoute에 대해서 알아보자. 영어에서 syntax는 문법, 구문론 등으로 해석되며, qoute는 `으로 “인용하다.” 또는 “전달하다.”로 해석된다.

그럼 Clojure에서는 어떻게 사용될까?

클로저에서 메서드에 syntax qoute를 사용했을 때 말 그대로 메서드 자체(구문론 자체를)를 그대로 전달하라는 의미를 갖는다. 아래와 같다.


user> `(+ 1 1) (clojure.core/+ 1 1)

위와 같이 심볼 자체로 출력된다. unqoute는 이때 사용된다. 심볼을 평가하고 싶을때 아래와 같이 사용된다.


user>`~(+ 1 1) 2

심볼을 평가하고 싶을때 unqoute를 사용하면 된다.

위와 같이만 예로 들 경우 어디에서 사용해야 하는지 감이 제대로 잡히지 않는다. 좀 더 깊히 들어가보자.


user> (def three-and-four (list 3 4))

\'user/three-and-four

user> `(1 three-and-four)

어떤 값이 나올까? 예상하는 바와 같이 아래와 같이 출력된다. \'user/three-and-four

평가되지 않았다. 위 unqoute때문에 평가되지 않았다. 이때 1은 data이므로 평가하지 않아야하고 three-and-four만 평가를 하고 싶을때 아래와 같이 사용할 수 있다.

user>`(1 ~three-and-four)

어떻게 될까? (1 (2 3))


위와 같이 평가되어 위와 같이 출력된다.


다음장에서 ~@ unquote splicing macro를 사용하여 다른값을 유추해보자.

Clojure – 특정 폴더에서 파일들을 읽어오고 싶을때

상황

특정 폴더에서 파일 들을 읽어오고 싶을 때가 있다 이럴 때는 어떻게 해야할까?

문제 해결

Tip 아래의 방법을 이용하여 샘플 폴더와 샘플 파일들을 만들어보자. (리눅스 또는 맥 환경에서)

$ mkdir -p next-gem
$ touch next-gen/picard.jpg next-gen/locutus.bmp next-gen/data.txt

java.io.File 객체들을 lazy sequence로 받기 위해 file-seq 함수를 사용 할 수 있다.

(def tag-dir (file-seq (clojure.java.io/file "./next-gen")))

tng-dir
;; -> (#<File ./next-gen>
;;     #<File ./next-gen/picard.jpg>
;;     #<File ./next-gen/locutus.bmp>
;;     #<File ./next-gen/data.txt>)

시퀀스는 클로저에서 좀더 파워풀하게 표현하는 추상적인 개념이다. map또는 filter함수를 사용하여 디렉토리 계층에 있는 것들을 재사용할 수 있다.

주의사항으로 만약 디렉토리가 아닐 파일만 필요할 경우 파일 객체의 .isFile 속성을 사용하길 권장한다.

(defn only-files
[files]
(filter #(.isFile %) files))
(only-files tng-dir)
;; -> (#<File ./next-gen/data.txt>
;;     #<File ./next-gen/locutus.bmp>
;;     #<File ./next-gen/picard.jpg>)

만약 파일명만 보여주고 싶다면 파일객체의 .getName을 이용하자.

(defn names
[files]
(map #(.getName %) files))

(-> tng-dir only-files names)
;; -> ("data.txt" "locutus.bmp" "picard.jpg")

이상!

Clojure – appengine-magic

현재 5.1버전까지 나온 appegine-magic은 leiningen 2.0이 필요하다. 그리고 Java는 1.6 또는 그 이후 버전이 필요하고 실제 구동을 시키면 몇 가지 에러가 발생되는데, 이 문제에 대해서는 5.0 사용을 권하고 있다.

몇 가지 테스트 결과 의존 되는 라이브러리 때문에 진행이 안되는 것이며, 이 문제는 간단하게 해결할 수 있었다. 수동으로 의존되는 라이브러리를 추가하면 되는 것이다.

이상으로 끄적끄적이였다.

Clojure – TCP Server Socket

ref

(require '[clojure.java.io :as io])
(import '[java.net ServerSocket])

(defn receive
  "Read a line of textual data from the given socket"
  [socket]
  (.readLine (io/reader socket)))

(defn send
  "Send the given string message out over the given socket"
  [socket msg]
  (let [writer (io/writer socket)]
      (.write writer msg)
      (.flush writer)))

(defn serve [port handler]
  (with-open [server-sock (ServerSocket. port)
              sock (.accept server-sock)]
    (let [msg-in (receive sock)
          msg-out (handler msg-in)]
      (send sock msg-out))))
(serve 8888 #(.toUpperCase %))

Clojure > How to list the functions of a namespace.

ref

(keys (ns-publics 'foo))

to list Vars exported by the namespace foo; e.g. for clojure.contrib.monads this returns

(defmonad censor m-when-not m+write+m maybe-m maybe-t ...)

(the … stands for quite a lot more).

More generally, there’s a bunch of functions whose names start in ns- which list Vars by namespace, with certain additional criteria attached:

ns-map — the most general function of all, returns a map keyed by symbols (non-namespace-qualified symbols actually), where the value corresponding to each symbol is the Var or class that symbol resolves to in the given namespace.

ns-interns — like ns-map, but includes only the Vars interned in the given namespace (as opposed to Vars from other namespaces which are accessible from the given namespace due to a use or refer call or the implicit referral of Vars from clojure.core.

ns-publics — like ns-interns, but includes only the non-private Vars.

ns-imports — like ns-map, but includes only the entries whose values correspond to Java classes.

There’s also ns-aliases which lists symbols which can be used as shorthand aliases when referring to Vars from other namespaces; e.g. if you call (require ‘[clojure.contrib.math :as math]), ns-aliases will include an entry with the key of math (the symbol), whose value will be the actual namespace clojure.contrib.math. These mapping are not included in the map returned by ns-map.

or you can use as the following.

(dir clojure.string)