클로저를 배우면서 생기는 생각들..

283 views
Skip to first unread message

Chris Kim

unread,
Sep 1, 2015, 3:35:42 AM9/1/15
to Korean Clojure User Group
클로저를 배우면서 좀 익숙 해지나 싶더니 잘 이해가 되지 않는게 종종 나오네요.

솔직히 리습을 먼저 공부한 저로선 왜 이렇게 디자인 했을까 얹듯 이해가 되지 않는게 많습니다.

1. []는 백터에만 쓰는게 아니라 파라메터에서 사용하고, let에서 사용하고 뭔가 정규화되지 않아서 처음 배우는 입장에선 오히려 더 헷깔립니다. 백터만 빼고 모두 () 사용해도 전혀 상관 없을 것 같은데 말이죠. 리습이 좋왔던 점이 문법은 정말 단순하다 였는데 클로저는 리습을 알아도 배우기가 만만치 않네요.

2. 클로저는 () 를 리습보다는 생략하는 편인데 이게 오히려 코드 가독성을 떨어트리는 경향이 있는것 같습니다. ex) clojure : (let [x y z w])  , lisp: (let ((x y) (z w)))  바인딩이 여러개 냐열 될 경우 헷깔릴 수 있을듯요.  물론 아래로 늘려 쓰거가 중간에 , 를 사용해도 되지만, 전반적으로 느낌은 너무 심플하게 만들려고 하다 보니 가독성은 무시한것 같은 느낌이랄까..
()를 좀더 많이 사용하면 타이핑을 더 많이 해야하지만 가독성이 좋와지고 에디팅 하기도 더 편합니다. () 단위로 삭제나 이동이 편리하기땜에..

3. 리습은 class를 사용하기 때문에 오브젝트단위 관리가 편한데 클로저는 class 가 없기때문에 namespace를 가지고 관리를 하는것 같습니다. 쿠테여 class를 쓰지 않는 이유를 잘 모르겠네요.. inheritance 등 편리한 기능들이 나름 있을듯 한데.. multimethod dispatch 도 클라스를 사용하지 않고 구현 하려다 보니 뭔가 어쩡쩡한 느낌이고 해킹같은 느낌이 강하게 드네요. class를 쓰지 않기 때문에 meta object programming 도 지원 안할테고 여튼 득보다 실이 많은 느낌??

4. 클로저는 뭔가 직관적이지 않은것들이 많은것 같습니다. 뒤져보면 방법이 있긴 한데 뭔가 좀 해킹을 하고 있다는 느낌이 듭니다. 한 예로  (for [ x [1 2] y [3 4]] (print x y)) 이러면 (1 3) (2 4) 이렇게 프린트가 될것 같은데 강제로 nested 가 되면서 (1 3) (1 4) (2 3) (2 4) 가 프린트된다는데서 깜짝 놀랐습니다. 이건 디자인 적으로 에러가 아닌가 싶네요. 기본적으로는 unnested for loop 이 맞을 것 같고 nested for loop 이 필요하다면 그냥 (for [x [1 2]] (for [y 3 4] (print x y))) 하면 되는데 말이죠.. unnested for loop 은 불가능 한가요? 음...

물론 장점도 많은것 같습니다. 그래서 더 아쉽다는.. ^^
여하튼 좀더 배우면서 나중엔 제 질문에 대해 다시 곱씹어 보면서 왜 그런지 하나 하나 이해 했으면 합니다.
Message has been deleted
Message has been deleted
Message has been deleted

aJchemist

unread,
Sep 1, 2015, 4:06:34 AM9/1/15
to Korean Clojure User Group
1. bracket notation은 special form을 구분할 수 있게 해줍니다. 파라미터 받을 때나 바인딩할 때 씁니다. 일관성이 있습니다. 중구난방은 아닙니다(설마요). 참고로 클로저는 파리미터로 받는 자리에서 바인딩까지 할 수 있습니다. e.g. [{:keys [a b]}]. 이상하군요 전 이게 참 좋던데요.
2. ,나 스페이스를 동일시하기 때문에 얻은 syntatic sugar 정도가 아닐까 생각합니다. 이 역시 적응되면 오히려 더 깔끔하게 보입니다.(콩깍지)
3. 대신 protocol 모델이 있죠. protocol은 개인적으로 오브젝트 시스템보다 더 해피해킹 친화적인 느낌입니다.
4. (map print [1 2] [3 4])가 있는데 for를 쓸 필요가 있을까요?

대충 생각난것들을 적어보았습니다. 저도 클로저 쌩초보라서 더 다양한 의견을 들어보고 싶군요.

pego...@gmail.com

unread,
Sep 1, 2015, 5:06:38 AM9/1/15
to Korean Clojure User Group

1. []는 백터에만 쓰는게 아니라 파라메터에서 사용하고, let에서 사용하고 뭔가 정규화되지 않아서 처음 배우는 입장에선 오히려 더 헷깔립니다. 백터만 빼고 모두 () 사용해도 전혀 상관 없을 것 같은데 말이죠. 리습이 좋왔던 점이 문법은 정말 단순하다 였는데 클로저는 리습을 알아도 배우기가 만만치 않네요.

기존 리습과 차별화 된것 처럼 포장하기 위해서는 타이핑 줄이면서 실제로는 차이 없으면서도 차이 있는 것 처럼 보이게 만드는게 중요했으리라 봅니다.

 

2. 클로저는 () 를 리습보다는 생략하는 편인데 이게 오히려 코드 가독성을 떨어트리는 경향이 있는것 같습니다. ex) clojure : (let [x y z w])  , lisp: (let ((x y) (z w)))  바인딩이 여러개 냐열 될 경우 헷깔릴 수 있을듯요.  물론 아래로 늘려 쓰거가 중간에 , 를 사용해도 되지만, 전반적으로 느낌은 너무 심플하게 만들려고 하다 보니 가독성은 무시한것 같은 느낌이랄까..
()를 좀더 많이 사용하면 타이핑을 더 많이 해야하지만 가독성이 좋와지고 에디팅 하기도 더 편합니다. () 단위로 삭제나 이동이 편리하기땜에..

뭐 익숙해 지면 거의 동일합니다만, 언급하신 문제가 있으므로 뉴라인이나 인덴테이션에 더 신경쓰게 됩니다.
 

3. 리습은 class를 사용하기 때문에 오브젝트단위 관리가 편한데 클로저는 class 가 없기때문에 namespace를 가지고 관리를 하는것 같습니다. 쿠테여 class를 쓰지 않는 이유를 잘 모르겠네요.. inheritance 등 편리한 기능들이 나름 있을듯 한데.. multimethod dispatch 도 클라스를 사용하지 않고 구현 하려다 보니 뭔가 어쩡쩡한 느낌이고 해킹같은 느낌이 강하게 드네요. class를 쓰지 않기 때문에 meta object programming 도 지원 안할테고 여튼 득보다 실이 많은 느낌??


namespace는 package에 대응됩니다. 착각하신 것이 있는데, 클로져는 함수형 언어이지 객체지향 언어가 아니라는 점입니다. 쉽게 말씀드리면 Common Lisp이 Clojure의 수퍼셋이라 보시면 될 겁니다. multimethod는 oop의 그것이 아니라 타입시스템과는 별개의 함수 디스패치하는 방법이죠. 당연히 OOP를 하자고 하면 잘 안됩니다. OO 언어가 아니라 MOP도 당연히 존재하지 않는 것이죠.

그런데 희안한 것이 일단 익숙해지면 CLOS 같은 것이 전혀 그립지 않게 된다는 점입니다.

 
4. 클로저는 뭔가 직관적이지 않은것들이 많은것 같습니다. 뒤져보면 방법이 있긴 한데 뭔가 좀 해킹을 하고 있다는 느낌이 듭니다. 한 예로  (for [ x [1 2] y [3 4]] (print x y)) 이러면 (1 3) (2 4) 이렇게 프린트가 될것 같은데 강제로 nested 가 되면서 (1 3) (1 4) (2 3) (2 4) 가 프린트된다는데서 깜짝 놀랐습니다. 이건 디자인 적으로 에러가 아닌가 싶네요. 기본적으로는 unnested for loop 이 맞을 것 같고 nested for loop 이 필요하다면 그냥 (for [x [1 2]] (for [y 3 4] (print x y))) 하면 되는데 말이죠.. unnested for loop 은 불가능 한가요? 음...


맞습니다. 그래서 저는 for를 잘 안씁니다. 굳이 하려면 다음과 같이 해야 하죠

(for [[x y] (map vector [1 2] [3 4])]
        (println (* x y)))

그런데 위 코드는 사실 위험한 코드입니다. 클로져에서는 side effect가 목적이라면 lazy sequence를 리턴하는 operation은 버그를 유발 할 수 있기 때문이죠.

그래서 순수 side effect를 위한 operation을 하는 것이 버그를 미연에 방지하는 방법입니다.

(doseq [[x y] (map vector [1 2] [3 4])]
        (println (* x y)))

map을 이용한 것도 lazy sequence가 리턴되기 때문에 비추입니다(만, 최근 버전에서는 버그인지 non lazy 가 되더군요)

 
물론 장점도 많은것 같습니다. 그래서 더 아쉽다는.. ^^
여하튼 좀더 배우면서 나중엔 제 질문에 대해 다시 곱씹어 보면서 왜 그런지 하나 하나 이해 했으면 합니다.

까놓고 보자면 마음에 안드는 부분도 꽤 있습니다. 예를들자면 falsey value 인데요. if 등에서 false 나 nil은 falsey value인 반면 #{} {} () [] 등은 truthy value 입니다.
저는 (empty? ...)를 많이 사용하는데요, 추천하는 방법은 (seq ...)를 사용하는 겁니다. seq는 predicate가 아니고 conversion function이라 저는 이렇게 된 코드를 보면 짜증이 나더군요.
아무튼 2% 부족한 느낌이 드는 설계라 봅니다.

또 이게 개인의 재산이다 보니, 기능의 추가나 언어의 확장이 좀 이해 안갈 때가 있는데 이건 뭐 요즘은 흔한 방식이니까요.

가장 큰 장점을 저는 현존하는 최고의 GC 기반 JVM에서 움직이는 Lisp이고 (제대로 쓸 수 있다면) 방대한 Java 라이브러리가 가장 큰 매력이라는 생각입니다. 또, Lisp 일은 많지 않지만, Clojure 일은 꽤 많거든요.

김영태

unread,
Sep 1, 2015, 5:10:45 AM9/1/15
to Korean Clojure User Group
다음은 질문하신 내용들에 대한 저의 의견입니다. 저의 의견들 중에는 저의 개인적 취향도
포함되어 있음을 미리 밝힙니다.

1. []는 백터에만 쓰는게 아니라 파라메터에서 사용하고, let에서 사용하고 뭔가 정규화되지
않아서 처음 배우는 입장에선 오히려 더 헷깔립니다. 백터만 빼고 모두 () 사용해도 전혀 상관
없을 것 같은데 말이죠. 리습이 좋왔던 점이 문법은 정말 단순하다 였는데 클로저는 리습을
알아도 배우기가 만만치 않네요.

[]는 벡터 리터럴을 표현하거나 binding-forms(let binding, function paameter binding, loop
binding, doseq binding, for bidning, ...)을 만들 때 사용됩니다. 이 두 가지 경우를
제외하고는 달리 쓰이지 않습니다. 아마도 binding-form이라는 공통점을 놓치셔서 오는 혼란인
것 같습니다.

그리고 클로저가 Common Lisp보다 익혀야 할 표기법이 많다는 점은 저도 인정합니다. 하지만 맵
자료형을 생성할 때도, (hash-map ...) 식보다는 {...}의 리터럴 방식이 저는 편하고 더
좋습니다. 그리고 이런 리터럴 방식이 DSL을 만들 때에도 훨씬 편리하고요. Common Lisp의
경우는 reader macro를 만들어 해결할 수도 있겠지만, 클로저에서는 reader macro의 도입으로
초래되는 코드의 복잡성을 피하기 위해 reader macro 생성을 원천적으로 허용하지 않기에, 언어
차원에서 리터럴 방식을 제공해 주어야만 합니다. 그리고 클로저가 지원하는 자료형의 수가 얼마
안되기 때문에 리터럴의 수가 많다고 보기도 힘듭니다.


2. 클로저는 () 를 리습보다는 생략하는 편인데 이게 오히려 코드 가독성을 떨어트리는 경향이
있는것 같습니다. ex) clojure : (let [x y z w]) , lisp: (let ((x y) (z w))) 바인딩이 여러개
냐열 될 경우 헷깔릴 수 있을듯요.  물론 아래로 늘려 쓰거가 중간에 , 를 사용해도 되지만,
전반적으로 느낌은 너무 심플하게 만들려고 하다 보니 가독성은 무시한것 같은 느낌이랄까..
()를 좀더 많이 사용하면 타이핑을 더 많이 해야하지만 가독성이 좋와지고 에디팅 하기도 더
편합니다. () 단위로 삭제나 이동이 편리하기땜에..

클로저는 괄호의 사용을 최대한 적게 사용하는 쪽을 선택했습니다. 그리고 저는 괄호의 사용을
줄인 것이 가독성을 떨어뜨리기보다는 오히려 높여 준다고 봅니다. 시각적으로 볼 때 괄호가
적은 것이 코드 이해에 더 도움이 되기 때문입니다. 물론 이로 인해서 초래되는 불편함도 없는
것은 아닙니다. 제가 제일 불편하게 느끼는 점은 #_ reader macro를 사용해서 form을 comment
out할 때 binding vector나 map 안에서는 항상 쌍으로 표기해 주어야 한다는 점 정도입니다.


3. 리습은 class를 사용하기 때문에 오브젝트단위 관리가 편한데 클로저는 class 가 없기때문에
namespace를 가지고 관리를 하는것 같습니다. 쿠테여 class를 쓰지 않는 이유를 잘
모르겠네요.. inheritance 등 편리한 기능들이 나름 있을듯 한데.. multimethod dispatch 도
클라스를 사용하지 않고 구현 하려다 보니 뭔가 어쩡쩡한 느낌이고 해킹같은 느낌이 강하게
드네요. class를 쓰지 않기 때문에 meta object programming 도 지원 안할테고 여튼 득보다 실이
많은 느낌??

클로저는 함수형 언어를 지향하는 리습입니다. 이에 관련한 대답은 예전에 제가 써놓은 글로
대신하겠습니다.



4. 클로저는 뭔가 직관적이지 않은것들이 많은것 같습니다. 뒤져보면 방법이 있긴 한데 뭔가 좀
해킹을 하고 있다는 느낌이 듭니다. 한 예로 (for [ x [1 2] y [3 4]] (print x y)) 이러면 (1
3) (2 4) 이렇게 프린트가 될것 같은데 강제로 nested 가 되면서 (1 3) (1 4) (2 3) (2 4) 가
프린트된다는데서 깜짝 놀랐습니다. 이건 디자인 적으로 에러가 아닌가 싶네요. 기본적으로는
unnested for loop 이 맞을 것 같고 nested for loop 이 필요하다면 그냥 (for [x [1 2]] (for
[y 3 4] (print x y))) 하면 되는데 말이죠.. unnested for loop 은 불가능 한가요? 음...

원하시는 작업은 (map (fn [x y] [x y]) [1 2] [3 4])와 같은 방식으로 처리가
가능합니다. 그리고 for는 원래부터 nested iteration 지원을 목적으로 설계된
매크로입니다. 그래서 실제로 logic 프로그래밍할 떄 많애 쓰입니다. logic 프로그래밍의
경우에는 중첩의 깊이가 2--3 단계 이상인 경우도 아주 흔한데, 그런 경우를 대비해 미리 만들어
놓은 매크로로 이해하시는 것이 좋습니다.

그런 의미에서, 중첩이 아주 많은 경우에는 다음의 첫 번쨰 코드가 두 번째 코드보다 낫다고
저는 봅니다만.

(for [a [1 2 3 4 5]
      b [6 7 8 9 10]
      c [11 12 13 14 15]
      d [16 17 18 19 20]
      e [21 22 23 24 25]]
  [a b c d e])

(for [a [1 2 3 4 5]]
  (for [b [6 7 8 9 10]]
    (for [c [11 12 13 14 15]]
      (for [d [16 17 18 19 20]]
        (for [e [21 22 23 24 25]]
          [a b c d e])))))


2015년 9월 1일 화요일 오후 4시 35분 42초 UTC+9, Chris Kim 님의 말:

Chris Kim

unread,
Sep 1, 2015, 6:50:34 AM9/1/15
to Korean Clojure User Group


2015년 9월 1일 화요일 오후 5시 6분 34초 UTC+9, aJchemist 님의 말:
1. bracket notation은 special form을 구분할 수 있게 해줍니다. 파라미터 받을 때나 바인딩할 때 씁니다. 일관성이 있습니다. 중구난방은 아닙니다(설마요). 참고로 클로저는 파리미터로 받는 자리에서 바인딩까지 할 수 있습니다. e.g. [{:keys [a b]}]. 이상하군요 전 이게 참 좋던데요.

그렇군요.. 바인딩과 관련된것만 기억 하면 되겠네요.. ^^
 
2. ,나 스페이스를 동일시하기 때문에 얻은 syntatic sugar 정도가 아닐까 생각합니다. 이 역시 적응되면 오히려 더 깔끔하게 보입니다.(콩깍지)

네.. 얼마나 빨리 익숙해지나 봐야겠네요. 그리고 리습코드를 보면??
 
3. 대신 protocol 모델이 있죠. protocol은 개인적으로 오브젝트 시스템보다 더 해피해킹 친화적인 느낌입니다.

함 살펴보도록 하겠습니다.
 
4. (map print [1 2] [3 4])가 있는데 for를 쓸 필요가 있을까요?

요런 방법이 있었군요.. 클로저를 배우는건 계속 뭔가 껍질을 까는 것 같은 느낌이네요. ㅋㅋ
 

Chris Kim

unread,
Sep 1, 2015, 6:56:19 AM9/1/15
to Korean Clojure User Group, pego...@gmail.com


2015년 9월 1일 화요일 오후 6시 6분 38초 UTC+9, pego...@gmail.com 님의 말:

1. []는 백터에만 쓰는게 아니라 파라메터에서 사용하고, let에서 사용하고 뭔가 정규화되지 않아서 처음 배우는 입장에선 오히려 더 헷깔립니다. 백터만 빼고 모두 () 사용해도 전혀 상관 없을 것 같은데 말이죠. 리습이 좋왔던 점이 문법은 정말 단순하다 였는데 클로저는 리습을 알아도 배우기가 만만치 않네요.

기존 리습과 차별화 된것 처럼 포장하기 위해서는 타이핑 줄이면서 실제로는 차이 없으면서도 차이 있는 것 처럼 보이게 만드는게 중요했으리라 봅니다.

 

2. 클로저는 () 를 리습보다는 생략하는 편인데 이게 오히려 코드 가독성을 떨어트리는 경향이 있는것 같습니다. ex) clojure : (let [x y z w])  , lisp: (let ((x y) (z w)))  바인딩이 여러개 냐열 될 경우 헷깔릴 수 있을듯요.  물론 아래로 늘려 쓰거가 중간에 , 를 사용해도 되지만, 전반적으로 느낌은 너무 심플하게 만들려고 하다 보니 가독성은 무시한것 같은 느낌이랄까..
()를 좀더 많이 사용하면 타이핑을 더 많이 해야하지만 가독성이 좋와지고 에디팅 하기도 더 편합니다. () 단위로 삭제나 이동이 편리하기땜에..

뭐 익숙해 지면 거의 동일합니다만, 언급하신 문제가 있으므로 뉴라인이나 인덴테이션에 더 신경쓰게 됩니다.
 

3. 리습은 class를 사용하기 때문에 오브젝트단위 관리가 편한데 클로저는 class 가 없기때문에 namespace를 가지고 관리를 하는것 같습니다. 쿠테여 class를 쓰지 않는 이유를 잘 모르겠네요.. inheritance 등 편리한 기능들이 나름 있을듯 한데.. multimethod dispatch 도 클라스를 사용하지 않고 구현 하려다 보니 뭔가 어쩡쩡한 느낌이고 해킹같은 느낌이 강하게 드네요. class를 쓰지 않기 때문에 meta object programming 도 지원 안할테고 여튼 득보다 실이 많은 느낌??


namespace는 package에 대응됩니다. 착각하신 것이 있는데, 클로져는 함수형 언어이지 객체지향 언어가 아니라는 점입니다. 쉽게 말씀드리면 Common Lisp이 Clojure의 수퍼셋이라 보시면 될 겁니다. multimethod는 oop의 그것이 아니라 타입시스템과는 별개의 함수 디스패치하는 방법이죠. 당연히 OOP를 하자고 하면 잘 안됩니다. OO 언어가 아니라 MOP도 당연히 존재하지 않는 것이죠.

그런데 희안한 것이 일단 익숙해지면 CLOS 같은 것이 전혀 그립지 않게 된다는 점입니다.

그런가요? 전 우선 클라스를 생각하게 되서.. 툴로 예기하자면 다용도 툴을 버리고, 단순 툴로 작업 하는것 같은. 그리고 Functional Programming 과 OOP는 반대되는 개념은 아니라고 봅니다. OOP는 또하나의 툴을 주워지는 개념이라고 생각해서 포기하려니 좀 아쉽다는..^^
 
 
4. 클로저는 뭔가 직관적이지 않은것들이 많은것 같습니다. 뒤져보면 방법이 있긴 한데 뭔가 좀 해킹을 하고 있다는 느낌이 듭니다. 한 예로  (for [ x [1 2] y [3 4]] (print x y)) 이러면 (1 3) (2 4) 이렇게 프린트가 될것 같은데 강제로 nested 가 되면서 (1 3) (1 4) (2 3) (2 4) 가 프린트된다는데서 깜짝 놀랐습니다. 이건 디자인 적으로 에러가 아닌가 싶네요. 기본적으로는 unnested for loop 이 맞을 것 같고 nested for loop 이 필요하다면 그냥 (for [x [1 2]] (for [y 3 4] (print x y))) 하면 되는데 말이죠.. unnested for loop 은 불가능 한가요? 음...


맞습니다. 그래서 저는 for를 잘 안씁니다. 굳이 하려면 다음과 같이 해야 하죠

(for [[x y] (map vector [1 2] [3 4])]
        (println (* x y)))

그런데 위 코드는 사실 위험한 코드입니다. 클로져에서는 side effect가 목적이라면 lazy sequence를 리턴하는 operation은 버그를 유발 할 수 있기 때문이죠.

그래서 순수 side effect를 위한 operation을 하는 것이 버그를 미연에 방지하는 방법입니다.

(doseq [[x y] (map vector [1 2] [3 4])]
        (println (* x y)))

map을 이용한 것도 lazy sequence가 리턴되기 때문에 비추입니다(만, 최근 버전에서는 버그인지 non lazy 가 되더군요)

자세히 보면 이해 하겠는데 언듯 보면 뭔가 암호같네요.. ㅋㅋ 
 
 
물론 장점도 많은것 같습니다. 그래서 더 아쉽다는.. ^^
여하튼 좀더 배우면서 나중엔 제 질문에 대해 다시 곱씹어 보면서 왜 그런지 하나 하나 이해 했으면 합니다.

까놓고 보자면 마음에 안드는 부분도 꽤 있습니다. 예를들자면 falsey value 인데요. if 등에서 false 나 nil은 falsey value인 반면 #{} {} () [] 등은 truthy value 입니다.
저는 (empty? ...)를 많이 사용하는데요, 추천하는 방법은 (seq ...)를 사용하는 겁니다. seq는 predicate가 아니고 conversion function이라 저는 이렇게 된 코드를 보면 짜증이 나더군요.
아무튼 2% 부족한 느낌이 드는 설계라 봅니다.

또 이게 개인의 재산이다 보니, 기능의 추가나 언어의 확장이 좀 이해 안갈 때가 있는데 이건 뭐 요즘은 흔한 방식이니까요.

가장 큰 장점을 저는 현존하는 최고의 GC 기반 JVM에서 움직이는 Lisp이고 (제대로 쓸 수 있다면) 방대한 Java 라이브러리가 가장 큰 매력이라는 생각입니다. 또, Lisp 일은 많지 않지만, Clojure 일은 꽤 많거든요.

네.. 그래서 저도 클로저를 배우려구요.. Lisp는 너무 오랜동안 정체된데다 fragmentation이 심해서.. ㅠㅠ

감사합니다.
 

Chris Kim

unread,
Sep 1, 2015, 7:20:25 AM9/1/15
to Korean Clojure User Group


2015년 9월 1일 화요일 오후 6시 10분 45초 UTC+9, 김영태 님의 말:
다음은 질문하신 내용들에 대한 저의 의견입니다. 저의 의견들 중에는 저의 개인적 취향도
포함되어 있음을 미리 밝힙니다.

1. []는 백터에만 쓰는게 아니라 파라메터에서 사용하고, let에서 사용하고 뭔가 정규화되지
않아서 처음 배우는 입장에선 오히려 더 헷깔립니다. 백터만 빼고 모두 () 사용해도 전혀 상관
없을 것 같은데 말이죠. 리습이 좋왔던 점이 문법은 정말 단순하다 였는데 클로저는 리습을
알아도 배우기가 만만치 않네요.

[]는 벡터 리터럴을 표현하거나 binding-forms(let binding, function paameter binding, loop
binding, doseq binding, for bidning, ...)을 만들 때 사용됩니다. 이 두 가지 경우를
제외하고는 달리 쓰이지 않습니다. 아마도 binding-form이라는 공통점을 놓치셔서 오는 혼란인
것 같습니다.

그리고 클로저가 Common Lisp보다 익혀야 할 표기법이 많다는 점은 저도 인정합니다. 하지만 맵
자료형을 생성할 때도, (hash-map ...) 식보다는 {...}의 리터럴 방식이 저는 편하고 더
좋습니다. 그리고 이런 리터럴 방식이 DSL을 만들 때에도 훨씬 편리하고요. Common Lisp의
경우는 reader macro를 만들어 해결할 수도 있겠지만, 클로저에서는 reader macro의 도입으로
초래되는 코드의 복잡성을 피하기 위해 reader macro 생성을 원천적으로 허용하지 않기에, 언어
차원에서 리터럴 방식을 제공해 주어야만 합니다. 그리고 클로저가 지원하는 자료형의 수가 얼마
안되기 때문에 리터럴의 수가 많다고 보기도 힘듭니다.


네.. 클로저는 단순한줄 알고 덤볐다가 좀 움찔 하고 있는 중입니다.. ㅋㅋ
reader macro를 지원 안한다고 해서 저도 사실 좀 실망했는데.. 발전하다보면 나중에 가능하지 않을까 합니다.
일단 심플 -> 기능 추가 이게 수순아닐런지.. ㅋㅋ 


2. 클로저는 () 를 리습보다는 생략하는 편인데 이게 오히려 코드 가독성을 떨어트리는 경향이
있는것 같습니다. ex) clojure : (let [x y z w]) , lisp: (let ((x y) (z w))) 바인딩이 여러개
냐열 될 경우 헷깔릴 수 있을듯요.  물론 아래로 늘려 쓰거가 중간에 , 를 사용해도 되지만,
전반적으로 느낌은 너무 심플하게 만들려고 하다 보니 가독성은 무시한것 같은 느낌이랄까..
()를 좀더 많이 사용하면 타이핑을 더 많이 해야하지만 가독성이 좋와지고 에디팅 하기도 더
편합니다. () 단위로 삭제나 이동이 편리하기땜에..

클로저는 괄호의 사용을 최대한 적게 사용하는 쪽을 선택했습니다. 그리고 저는 괄호의 사용을
줄인 것이 가독성을 떨어뜨리기보다는 오히려 높여 준다고 봅니다. 시각적으로 볼 때 괄호가
적은 것이 코드 이해에 더 도움이 되기 때문입니다. 물론 이로 인해서 초래되는 불편함도 없는
것은 아닙니다. 제가 제일 불편하게 느끼는 점은 #_ reader macro를 사용해서 form을 comment
out할 때 binding vector나 map 안에서는 항상 쌍으로 표기해 주어야 한다는 점 정도입니다.


3. 리습은 class를 사용하기 때문에 오브젝트단위 관리가 편한데 클로저는 class 가 없기때문에
namespace를 가지고 관리를 하는것 같습니다. 쿠테여 class를 쓰지 않는 이유를 잘
모르겠네요.. inheritance 등 편리한 기능들이 나름 있을듯 한데.. multimethod dispatch 도
클라스를 사용하지 않고 구현 하려다 보니 뭔가 어쩡쩡한 느낌이고 해킹같은 느낌이 강하게
드네요. class를 쓰지 않기 때문에 meta object programming 도 지원 안할테고 여튼 득보다 실이
많은 느낌??

클로저는 함수형 언어를 지향하는 리습입니다. 이에 관련한 대답은 예전에 제가 써놓은 글로
대신하겠습니다.


네.. 정독은 하지 않았지만 눈에 들어오는 말은 단순/복잡/Immutability/FP/OOP등이네요. FP 와 OOP는 상관관계는 아니라고 생각하고 클로저는 immutability가 가장 큰 특징이라 OOP는 기본적으로 상태를 포함함으로 immutablility를 제대로 구현하려면 쉽지 않기때문에 피한게 아닌가 싶습니다. OOP를 안쓰고프로그래밍을 하는건 가능하지만 이는 마치 최첨단 밀링머신을 버리고 맨손으로 작업하는듯한 느낌이네요. OOP를 CLOS처럼 클로져 위에 구현하는건 불가능한 일일까요??  없어도 된다와 불가능하다와는 다르기때문에 걍 함 여쭤 봅니다. 지금 당장은 이부분이 가장 맘에 들지 않는데 나중에 어떻게 바뀌는지 저도 모르겠습니다. ㅎㅎ  
 

4. 클로저는 뭔가 직관적이지 않은것들이 많은것 같습니다. 뒤져보면 방법이 있긴 한데 뭔가 좀
해킹을 하고 있다는 느낌이 듭니다. 한 예로 (for [ x [1 2] y [3 4]] (print x y)) 이러면 (1
3) (2 4) 이렇게 프린트가 될것 같은데 강제로 nested 가 되면서 (1 3) (1 4) (2 3) (2 4) 가
프린트된다는데서 깜짝 놀랐습니다. 이건 디자인 적으로 에러가 아닌가 싶네요. 기본적으로는
unnested for loop 이 맞을 것 같고 nested for loop 이 필요하다면 그냥 (for [x [1 2]] (for
[y 3 4] (print x y))) 하면 되는데 말이죠.. unnested for loop 은 불가능 한가요? 음...

원하시는 작업은 (map (fn [x y] [x y]) [1 2] [3 4])와 같은 방식으로 처리가
가능합니다. 그리고 for는 원래부터 nested iteration 지원을 목적으로 설계된
매크로입니다. 그래서 실제로 logic 프로그래밍할 떄 많애 쓰입니다. logic 프로그래밍의
경우에는 중첩의 깊이가 2--3 단계 이상인 경우도 아주 흔한데, 그런 경우를 대비해 미리 만들어
놓은 매크로로 이해하시는 것이 좋습니다.

map 은 리스트를 리턴하기때문에 근본적으로 다른목적이라고 생각했는데 뭔가 찝찝한 느낌이 있긴 합니다. ^^

그런 의미에서, 중첩이 아주 많은 경우에는 다음의 첫 번쨰 코드가 두 번째 코드보다 낫다고
저는 봅니다만.

(for [a [1 2 3 4 5]
      b [6 7 8 9 10]
      c [11 12 13 14 15]
      d [16 17 18 19 20]
      e [21 22 23 24 25]]
  [a b c d e])

(for [a [1 2 3 4 5]]
  (for [b [6 7 8 9 10]]
    (for [c [11 12 13 14 15]]
      (for [d [16 17 18 19 20]]
        (for [e [21 22 23 24 25]]
          [a b c d e])))))

네.. 같은걸 두가지 방식으로 표현하는게 좋을지 아니면 차이를 둘지 호불호가 갈릴 수 있겠네요.. 클로저의 특징중에 하나가, 같은목적을 가진 함수를 다양하게 구현할수있다 인것도 같습니다. 근데 단순함을 추구하는 클로저가 다양한 방식으로 표현하는건 왠지 서로 상충하는것 같고.. for 같은 경우는 사실 아직도 좀 충격적입니다. 클로저를 모르는 사람이 봤을때 위 두 구문이 같은거라고 생각할까요?

클로저가 썩 맘에 들진 않지만 나름 배울 가치가 있다고 생각합니다.
유용성을 떠나서 솔찍히 언어로서는 (아직)맘에 쏙들지는 않네요. 그보다 여기 클로저 모임에 계시는 분들이 너무 좋은 분들이 많이 계서서 그게 가장 맘에듭니다. ^^

감사합니다.
 
 

김영태

unread,
Sep 1, 2015, 8:13:02 AM9/1/15
to Korean Clojure User Group
저의 개인적인 판단이기는 합니다만, Rich Hickey가 앞으로 reader macro 작성을 허용할 것 같지는 않습니다. 워낙 코드의 단순화에 대한 신념으로 똘똘 뭉친 사람이라서요. 하지만 저의 개인적으로 symbol macro는 열어주었으면 하는 바램이 있습니다. ^^

클로저로 Common LIsp의 CLOS같은 객체 지향 시스템을 개발하는 것이 불가능하지는 않을 겁니다. CLOS도 결국 리습의 매크로와 closure를 이용해 만든 것이니까요. 그런데 클로저 객체 지향 시스템의 개발은 함수형 프로그래밍의 관점에서 보면 역진화에 해당하기 때문에 나서는 사람이 많지는 않을 것 같습니다. ^^

클로저에서 상태를 변경하는 도구를 제공하기는 하지만, 일반 객체 지향에서의 멤버 변수 변경과는 다른 메커니즘으로 동작합니다. 

예를 들어, 자바에서 다음의 코드를 실행하면 

String s = "Hello";
s = s + " World";

아시다시피 자바의 문자열은 immutable이어서 변수 s는 "Hello World"라는 완전히 새로운 객체를 할당 받듯이

(def (atom a 10))
(def b @a)

(swap! a inc)

@a   ; => 11
b    ; => 10

위의 코드는 a의 값이 11로 변경되는 것이 아니라, 11이라는 완전히 새로운 객체를 할당받게 됩니다. 그래서 b가 여전히 이전의 10의 값을 반환하게 되지요. 여기에서 history라는 개념이 등장하게 됩니다. 그래서 객체 지향을 흉내내서 closure의 형식으로 함수 내부에 상태 변수를 지니고 멈버 변수처럼 접근할 수는 있지겠만, 객체 지향에서 상태값을 변경하는 것과는 작동 메커니즘이 많이 다릅니다.

객체 지향에서의 상태 변경은, 비유적으로 표현하면, 칠판에 글씨를 쓰는 것과 같습니다. 칠판이 다 차면 이전 내용을 지워야만하지요. 하지만 클로저에서의 상태 변경은 공책에 글을 쓰는 것에 비유할 수 있습니다. 한 페이지가 다 차면  다른 페이지에 계쏙 글을 채워 나가는 방식입니다.  그리고 이미 쓴 글은 어떤 방식으로든 절대 변경할 수 없습니다. 이미 쓴 글을 어디에선가 참조하고 있다면 그 내용은 garbage collecting되지 않고 메모리에 남아 있게 되고, 더 이상 참조되지 않는 값은 garbage collecting될 수는 있습니다. 조선시대 지조 곧은 선비를 연상하시면 되겠습니다. 죽으면 죽었지 나의 지조를 바꿀 수는 없다 정도로요,
  


  

2015년 9월 1일 화요일 오후 8시 20분 25초 UTC+9, Chris Kim 님의 말:

pego...@gmail.com

unread,
Sep 1, 2015, 5:46:33 PM9/1/15
to Korean Clojure User Group
언어 자체는 아닐지라도 Clojure 같은 언어가 Common Lisp 보다 나은 세상이 되었다고 봅니다.

- JVM의 발전으로 Lisp계열 언어에서 꼭 필요한 GC가 이미 상당한 경지에 도달하였고 그 위에서 돌아가는 Lisp은 상당히 유리한 위치를 차지할 수 있습니다.
- 클라우딩 컴퓨팅 시대가 열리면서 수평적 스케이링이 유리한 함수형 언어군이 각광을 받기 시작하였죠. 함수형 언어 중에서도 가장  쓸만한건 Clojure 정도 밖에 없다고 봅니다.
- 방대한 자바 라이브러리를 자유롭게 사용할 수 있는 언어가 그렇지 못한 언어보다 "일"을 빠르고 정확하게 끝내기에 유리하죠(하지만, 자바 라이브러리 쓰다보면 욕나옵니다)

언어자체는 저는 Common Lisp이 낫다고 봅니다. 워낙 똑똑한 사람들이 광범위하게 위원회를 통해서 만들어진 표준이 존재하기 때문에 일관성이 존재한다고나 할까요? Clojure 는 아직도 진화하는 단계라 어떨때는 좀 어수선한 느낌이 듭니다. 제 예상으로는 결국 Common Lisp 처럼 이런 저런 것들이 계속 추가되면서 초기 장점으로 광고되던 것들이 점점 사라지리라 봅니다. 

처음에 언급했듯이 이제 세상이 JVM 위에서 돌아가면서 방대한 라이브러리를 가져다 쓸 수 있는 함수형 언어가 살아남기 아주 유리하게 바뀌었다는 점 때문에 Clojure가 우위에 있게 되버린거죠.

전 이 모든 것이 그냥 우연히 그렇게 되었다고 봅니다. 리치히키의 펫 프로젝트가 우연히 시대를 잘 만나서 Common Lisp 같이 잘 정의된 언어를 제치고 메이저 대열에 들어선 거죠.

리치히키는 요즘은 immutable database 에 힘을 쏟는 듯 한데, 이것은 시대를 잘 살핀 후 펫프로젝트가 아닌 상업적 목적으로 하는 것 같은데, 저장장치 가격이 아주 저렴해졌지만, RDBMS와 NoSQL의 아성을 깨치고 상업적 성공을 거둘지는 모르겠습니다. 사실 RDBMS로 이거 구현은 그다지 어렵지는 않거든요

Jaeha Kim

unread,
Sep 1, 2015, 9:13:28 PM9/1/15
to Korean Clojure User Group
초짜 나부랭이라 조심스럽습니다만...

Clojure에서의 for 구문은 C/C++/Java 등의 for 와는 의미랄까? 쓰임새? 용법이? 많이 다르지 않나요...?

C/C++/Java 등에서의 '반복'을 위한 도구라기 보다는 

사실상 list comprehension 으로써 수학책 등에서 등장하는 for 에 가깝다고 알고 있습니다만...

뭐 그럼에도 불구하고...

님께서 예를 들어주신 (for [x [1 2]] (for [y 3 4] (print x y))) 같은 표현은 C/C++/Java 등에서 자주 나타나고 그 언어들이 아무래도 사용자층이 많다 보니 처음에는 저도 그 표현이 더 자연스럽긴 했습니다.

김영태

unread,
Sep 1, 2015, 9:25:00 PM9/1/15
to Korean Clojure User Group
list comprehension을 위한 용도가 맞습니다.

2015년 9월 2일 수요일 오전 10시 13분 28초 UTC+9, Jaeha Kim 님의 말:

김영태

unread,
Sep 1, 2015, 9:41:35 PM9/1/15
to Korean Clojure User Group
잠시 첨언하자면, 집합 이론에서 조건 제시법으로

S = { 2x | x is an element of natural number N }

하면, S 집합은 {2, 4, 6, 8, ...}의 결과값이 나오고

S = { (x, y) | x and y is an element of natural number N }

하면, S 집합은 { (1, 1), (1, 2), (1, 3), ..., (2, 1), (2, 2), (2, 3), ... }의 결과가 나오게 됩니다.

수학에서 집합의 원소가 반드시 1차원일 필요는 없고, 2차원일 수도, 3차원일 수도 아니면 
그 이상일 수도 있습니다.


2015년 9월 2일 수요일 오전 10시 25분 0초 UTC+9, 김영태 님의 말:

Taegyoon Kim

unread,
Sep 1, 2015, 10:26:45 PM9/1/15
to Korean Clojure User Group
 
장단점이 있더라구요. 괄호가 적으면 읽기는 편한데 편집이 어렵고..
 
이런 깊이 있는 비판이나 논의가 많아져야 Clojure 등 Lisp이 발전할 수 있다고 봅니다.
 
 
 

2015년 9월 1일 화요일 오후 4시 35분 42초 UTC+9, Chris Kim 님의 말:
클로저를 배우면서 좀 익숙 해지나 싶더니 잘 이해가 되지 않는게 종종 나오네요.

김영태

unread,
Sep 1, 2015, 11:20:51 PM9/1/15
to Korean Clojure User Group
클로저의 for 매크로를 한 마디로 요약해 보면, 집합의 '조건 제시법'처럼, 조건이 binding vector의 형태로 주어지면, 그 조건을 만족하는 모든 집함의 원소를 '원소 나열법'처럼 나열해 반환해 준다 입니다. 그리고 이 for 매크로의 side effect 버전이 doseq 매크로입니다. 그래서 for에서 제공하는 modifier인 :when :where :let을 doseq에서도 그대로 쓸 수 있습니다.

2015년 9월 2일 수요일 오전 10시 41분 35초 UTC+9, 김영태 님의 말:

김영태

unread,
Sep 1, 2015, 11:22:39 PM9/1/15
to Korean Clojure User Group
위의  :when :where :let을 :when :while :let으로 정정합니다.

2015년 9월 2일 수요일 오후 12시 20분 51초 UTC+9, 김영태 님의 말:

Chris Kim

unread,
Sep 2, 2015, 12:56:48 AM9/2/15
to Korean Clojure User Group
괄호가 적으면 읽기가 편하다는데 아직 맘에 동하지 않네요.. ^^
전 괄호가 있어야 구별이 편한데.. let 은 비교적 단순하기때문에 덜 헷깔리나,  예로 switch나 cond 같은 경우 body 가 길어질 수 있기 때문에 body 와 구분이 없으면 읽기가 꽤 난해 할듯 합니다.  말씀하신데로 s-expression comment out 하던가 에디팅도 더 힘들구요.. 하튼 이건 단순함이 좀 지나친 경우 같아 보입니다. 

(cond (<condition1>
         ...
         ...
         ...
         ...
         )
         (<body1>
          ...
          ...
          ...
          ...
          )
         (<condition2>
          ...
          ...
          ...
          ...
          )
          (<body2>
          ...
          ...
          ...
          ...
          ))





2015년 9월 2일 수요일 오전 11시 26분 45초 UTC+9, Taegyoon Kim 님의 말:

aJchemist

unread,
Sep 2, 2015, 1:15:41 AM9/2/15
to Korean Clojure User Group
클로저 병맛포인트를 잘 찾아내시는군요 ㅎㅎ

저도 cond 맘에 안듭니다. body를 쓰려면 (do body)로 써야해서 ugly해질때가 있습니다. (if cond then else)에서도 else는 커먼리습처럼 임의의 길이로 익스프레션이 올 수 있지만 클로저는 역시 (do ...) 해줘야하죠.

저도 리습은 emacs-lisp -> common-lisp -> clojure 순서로 와서 처음에는 마치 c++처럼 울며겨자먹기로 쓰기 시작했는데, 점점 익숙해지고 있습니다. 인간은 적응의 동물이니 금방 적응됩니다. 게다가 뭔가 리습코딩으로 애플리케이션 개발을 하려한다면 clojure로 올 수 밖에 없어보입니다. 해피해킹차원으로 커먼리습을 가지고 시스템 해킹은 얼마든지 한다지만, 앱개발로 보면 공정에 걸리는 시간이나 결과물의 질적인 차이가 너무 큽니다.

김영태

unread,
Sep 2, 2015, 1:50:20 AM9/2/15
to Korean Clojure User Group
저의 cond 대처법입니다.

일단 분기가 많으면 프로그램 로직의 복잡도가 증가합니다. 그래서 일단은 분기문을 쓰더라도, 요구 조건에 맞게 로직을 잘 분석해서, 최대로 분기의 수를 줄일 수 있는 한 줄입니다. 그후에 cond 내의 test expr 절에서, expr 부분을 짧은 코드의 경우에는 (do ...)를 사용하고, 긴 코드의 경우는 처리 로직을 별도의 함수로 빼냅니다. cond문 안에 모든 처리 로직을 집어 넣으면 전체적인 논리 흐름을 한 눈에 파악하기가 어려워서, 분기 로직과 처리 로직을 분리시킵니다. 그럼 양 쪽 모두 깔끔한 코드를 유지할 수 있습니다. 그리고 불가피한 경우가 아니면, 기본적으로 하나의 함수는 20줄 이내로 유지합니다. 

2015년 9월 2일 수요일 오후 1시 56분 48초 UTC+9, Chris Kim 님의 말:

plum...@gmail.com

unread,
Sep 2, 2015, 6:14:29 AM9/2/15
to cloju...@googlegroups.com
몇주전쯤에 잠깐 생각한건뎅
기본문법을
쓰고싶은 스타일을 설정해서 사용가능했으면 좋겠다는 잡생각을 해보았습니당 이맥스 셋팅처럼요

엊그제 
매크로는 정말 충격적이네용;;;
마치 저그 부화장소에서 부화되면서 코드가 합체되는... 캔디클러쉬 소다도 생각났습니다
ㅍㅎ 개인적으론 한차원 레이어에 정도에서 그냥 함수기능만 하면 더 쓰지 않는게 나을것도 같고용
경험과 연습이 필요할거같습니당
하지만
절대적으로 원래있던 함수를 다르게 동작 혹은 확장
분해해서 재조립하는데는 필요할것같아
(건들면 안되는 언어를 건드렸다 생각이 듭니다 
천재들이나 쓰는 언어 매크로기능)ㅋㅎ



나의 iPhone에서 보냄

2015. 9. 2. 오후 2:50 김영태 <phil...@gmail.com> 작성:

--
이 메일은 Google 그룹스 'Korean Clojure User Group' 그룹에 가입한 분들에게 전송되는 메시지입니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 clojure-kr+...@googlegroups.com에 이메일을 보내세요.
이 그룹에 게시하려면 cloju...@googlegroups.com에 이메일을 보내세요.
웹에서 이 토론을 보려면 https://groups.google.com/d/msgid/clojure-kr/d800bf73-30f7-4a53-b588-04a22f18ec92%40googlegroups.com을(를) 방문하세요.
더 많은 옵션을 보려면 https://groups.google.com/d/optout을(를) 방문하세요.

Chris Kim

unread,
Sep 2, 2015, 8:12:53 AM9/2/15
to cloju...@googlegroups.com
Macro 은 리습에서 타 언에 대비 가장 돋보이는 기능 이였습니다. DSL 를 만드는데 최적화 된 넘이라..
Macro 를 쓰다 보면 코드가 정말 아름답다라고 느껴지고 나는 예술을 하고 있구나 착각에 빠질 때가 있습니다.
클로저는 아직 보진 않았지만 또 어떤 차이가 숨어있을지 기대하고 있습니다. ^^
 
물론 Macro로 원하는 문법을 구현해 가면서 사용할 수 는 있겠지만 모든 사람이 사용하는 기본 문법이랑 차원이 다른 예기라..
그동안 클로저의 발전 과정을 봐보니.. 뭔가 큰 변화가 있길 기대는 안 하는게 좋을 것 같군요.
한 사람이 만든거라 개인 취향이 상당이 반영 되 있고 그냥 익숙해지는 수 밖에는 없을 듯 요.
이 메일은 Google 그룹스 'Korean Clojure User Group' 그룹의 주제에 가입한 분들에게 전송되는 메시지입니다.
이 주제에서 탈퇴하려면 https://groups.google.com/d/topic/clojure-kr/Gkrg1p0obxg/unsubscribe을(를) 방문하세요.
이 그룹 및 그룹의 모든 주제에서 탈퇴하려면 clojure-kr+...@googlegroups.com에 이메일을 보내세요.

이 그룹에 게시하려면 cloju...@googlegroups.com에 이메일을 보내세요.

더 많은 옵션을 보려면 https://groups.google.com/d/optout을(를) 방문하세요.



Avast logo

This email has been checked for viruses by Avast antivirus software.
www.avast.com


pego...@gmail.com

unread,
Sep 3, 2015, 6:29:34 AM9/3/15
to Korean Clojure User Group


On Wednesday, September 2, 2015 at 10:12:53 PM UTC+10, Chris Kim wrote:
Macro 은 리습에서 타 언에 대비 가장 돋보이는 기능 이였습니다. DSL 를 만드는데 최적화 된 넘이라..
Macro 를 쓰다 보면 코드가 정말 아름답다라고 느껴지고 나는 예술을 하고 있구나 착각에 빠질 때가 있습니다.
클로저는 아직 보진 않았지만 또 어떤 차이가 숨어있을지 기대하고 있습니다. ^^
 


클로져 매크로는 거의 차이없고 오히려 두가지 정도 소소하게 나은 점들이 있습니다. 근데 언어 자체가 매크로를 그닥 사용하지 않아도 되더군요.

 
 
물론 Macro로 원하는 문법을 구현해 가면서 사용할 수 는 있겠지만 모든 사람이 사용하는 기본 문법이랑 차원이 다른 예기라..
그동안 클로저의 발전 과정을 봐보니.. 뭔가 큰 변화가 있길 기대는 안 하는게 좋을 것 같군요.
한 사람이 만든거라 개인 취향이 상당이 반영 되 있고 그냥 익숙해지는 수 밖에는 없을 듯 요.


큰 변화가 계속 있었습니다. 예를들면 core.async 덕에 thread 프로그래밍 복잡도가 상당히 낮아졌죠.


제가 느끼는 가장 큰 문제는 의존성 문제입니다. 소소한 라이브러리 하나 버전 업그레이드 하려다가 라이브러리 몽땅 강제 업그레이드 해야 되는데,  호환 안되는 변경이 있으면 강제로 다 고쳐야 되더군요. 단단한 기반없이 흔들리는 바닦에서 계속 작업하는 느낌?
Reply all
Reply to author
Forward
0 new messages