"asdf-subdir-finder" released!

지난번 포스팅한 "asdf 정의를 내 코드베이스의 하위디렉토리에서 자동으로 로딩하기"를 프로젝트으로 만들었다.

https://github.com/ageldama/asdf-subdir-finder

사람마다 커먼리습으로 작업하는 스타일에 따라 많이 다를 수 있어서 안 써도 되기도 하지만, 그냥 정리해서 공개는 해봤다.

Read more...

"커먼리습 ASDF 불러오기 편하게 하기" 대모험

ASDF와 system definition file 검색의 정석 이전에 ASDF을 이용하여 커먼리습 프로젝트의 의존성, 시스템을 로딩하기 에 대해서 설명한 적이 있었다. 이전에 다룬 내용은 정석적으로 $HOME/common-lisp 디렉토리에 .asd 파일을 심볼릭링크를 걸고, (asdf:load-system ..) 을 시도하는 내용이었었다. Prototyping등 더 편안하게 혼자 코딩을 할 때는… 혼자 커먼리습 코딩을 하면서, 나는 더 간단하게 프로젝트를 시작하는 방법을 선호한다. 커먼리습이 파일 이름이나 경로에 대해서 의존하는 것이 아니고, 컴파일시점, 로딩시점에 순서에 따라 로딩해서 최종적으로 컴파일하여 적재한 결과 이미지를 더 중요하게 여기기 때문에, 그리고 그런 컴파일, 빌드, 로딩과 같은 모든 단계들 자체도 커먼리습 표현식 그자체로 동작하기 때문에 그냥 하나의 소스파일을 섹션별로 나눠서 작업하면 편리하다.
Read more...

CommonLisp (w/o LOOP-macro) / LeetCode "1614. max nesting depth of the parentheses"

어제 작성한 LOOP매크로을 이용한 구현 을 풀어서, 만약 LOOP매크로가 없었더라면 어떻게 짰을지 작성해봤다. (defun max-nested-parentheses-raw (s) (declare (optimize (speed 3) (safety 0)) (type simple-string s)) (let ((n 0) (result 0)) (declare (type fixnum n result)) (dotimes (s--cur-idx (length s)) (let ((ch (elt s s--cur-idx))) (when (member ch '(#\( #\))) (incf n (if (eql #\( ch) 1 -1)) (setf result (max n result))))) result)) 여전히 타입을 지정해서 자동으로 타입추론, 최적화 하도록 했다.
Read more...

CommonLisp / LeetCode "1614. max nesting depth of the parentheses"

문제 https://leetcode.com/problems/maximum-nesting-depth-of-the-parentheses/ 작성한 코드 (defun max-nested-parentheses (s) (declare (optimize (speed 3) (safety 0)) (type simple-string s)) (loop with n fixnum = 0 for ch across s when (member ch '(#\( #\))) do (incf n (if (eql #\( ch) 1 -1)) maximizing n)) 코드 의도 우아한 코드보다는 공간복잡도가 O(1) 이고 싶었다. Edit SBCL에 맞춰 코드에 타입을 지정해줘봤다.
Read more...

Ping 19/Oct/2020

가을 도르트문트 집은 꽤 평화로웠다. 날씨가 좋은 날도 많고 공기도 맑았다. 한가한 주말이 되면 창문을 열고 잔디가 깔린 정원을 보며 담배를 태우고 커피를 내려 마셨다. 그리고 지하세탁장에 빨래를 돌려놓고 핑크플로이드의 다크사이드 오브 더 문 앨범을 좋은 스피커로 틀어놓았다. 잘 어울렸다. 서울의 변두리에서 맞는 이번 가을은 그런 기분이다. 조용하고 가을 햇살과 공기가 맑아졌다. 그리고 핑크플로이드를 그렇게 여유롭게 들을 수 있었다. 오늘 읽으려는 글 http://www.
Read more...

Ping (2nd) 17/Oct/2020

올해 초 cl-state-machine 라이브러리를 만들어 공개한 이후로 커먼리습을 쓰지는 않았다. 다른 직업상 쓰는 언어들만을 쓰고 오픈소스와 개인적으로 만들고 싶은 프로젝트를 위해서 쓰는 언어인 커먼리습은 미뤄두었었다. 다시 커먼리습을 해야겠다고 생각이 들었다. 개인적으로 만들고 싶은 프로젝트도 있고, 그 프로젝트를 위해서 프론트엔드를 만드는데 React와 Vue을 써보고 이해하고 있어도 쓰고 싶지는 않기 때문이다. 사실 커먼리습은 그렇게 문법이 예쁘지도, 멋진 React와 같은 멋진 프레임웍이나 최신의 유행하는 라이브러리들을 모두 갖고 있지도 않다.
Read more...

Ping 17/Oct/2020

웹프론트엔드 개발을 조금씩 해보고 있다. 처음에는 예전 방식으로만 하려고 하다가 조금씩 겨우 써보던 webpack을 다시 가이드를 차근차근 공부하고 동작하는 방식을 이해하도록 뜯어보고 돌려봤다. 생각보다 단순하게, 그리고 확장성 있게 쓸만한 빌드도구였다. 다만 문제는 설정이 복잡하고 이해하기 힘든 점보다는 빌드 시간이 너무 느린 점이었다. (내게는) 그래서 parcel bundler을 시도 했는데, 설정도 거의 필요 없이 바로 동작하고 하는 점은 좋고, 성능도 정말 빨랐다. 다만 Vim/Emacs으로 파일을 편집하고 저장할 때, parcel watch 대상인 파일들을 종종 아예 dev-server을 재시작해야만 제대로 동작하는 상태로 빠지는게 조금 짜증났다.
Read more...

Ping 16/Oct/2020

ADT1만큼 만들어 쓰는 것은 아니지만, 그냥 Kotlin, Python의 dataclass 정도는 쓰고 싶어서 CommonLisp 매크로를 만들어봤다.2 equals 라이브러리를 써서 동치 비교와 CLOS의 print-object generic function을 구현해서 to-string 정도만 되도록 만들어 봤다. macro body (defmacro define-data-class (class-name parent-classes slot-names &key (no-print-slot-names nil) (no-equals-slot-names nil)) (flet ((accessor-symbol (slot-name) (alexandria:format-symbol *package* "~a-~a" class-name slot-name))) (list 'progn ;; defclass (let ((slot-defs (loop for slot-name in slot-names collecting `(,slot-name :initarg ,(alexandria:make-keyword slot-name) :accessor ,(accessor-symbol slot-name))))) `(defclass ,class-name ,parent-classes ,slot-defs)) ;; defmethod print-object (let* ((print-slot-names (set-difference slot-names no-print-slot-names)) (fmt-ctrl (format nil "~{~a=~~a~^, ~}" print-slot-names))) `(defmethod print-object ((obj ,class-name) stream) (print-unreadable-object (obj stream :type t) (with-slots ,print-slot-names obj (format stream ,fmt-ctrl ,@print-slot-names))))) ;; defmethod equals:equals (let* ((equals-slot-names (set-difference slot-names no-equals-slot-names)) (equals-exprs (loop for equals-slot-name in equals-slot-names collecting `(equals:equals (slot-value lhs (quote ,equals-slot-name)) (slot-value rhs (quote ,equals-slot-name)))))) `(defmethod equals:equals ((lhs ,class-name) (rhs ,class-name) &rest args) (declare (ignore args)) (and t ,@equals-exprs))) ))) synopsis / usage (define-data-class animal () (name age)) (define-data-class bird (animal) ()) (equals:equals (make-instance 'animal :name "foo" :age 18) (make-instance 'animal :name "foo" :age 18)) 오랬만에 재밌었다.
Read more...

Ping (2nd) 15/Oct/2020

… '田大'이라고 적혀 있었다. 다른 한문으로 쓰여 있어 읽지 못하는 각각의 수 많은 바램들과 이름들 사이로 삐뚤빼뚤한 어색한 글씨로 그렇게 적혀 있었었다. 너무 단순한 이름, 그리고 설명이 붙어 있었듯이, 다른 사람들처럼 많은 이야기를 적고 싶었지만, 아이여서 그랬는지, 아니면 글을 몰라 그랬는지, 이름만이라도 적어놓은 그 못그린 그림 같은 두 글자를 읽었다. 누군가 아주 오래 전에 그 사람도 아마도 나와 별로 다를 것도 없는 고민들을 하며 매일을 살았었던 것을 느꼈다.
Read more...

Ping 15/Oct/2020

예전에 다니던 회사의 소식을 뉴스로 봤다. 사고 자체는 그렇게 좋은 이야기는 아니어서 안타까웠었다. 그리고 나오기 이전에 팀의 문화나 프로세스, 방법론 같은 이야기를 대표와 많이 나누고 많은 글을 써서 전달한 것이, 관련 검색에 보이는 구인란에 잘 적혀있고 문화와 시스템에 반영된 것 같아서 기분이 정말 좋았다. 비록 그것에 대한 기여가 내 몫으로 내 이름을 빛나게 하거나 경제적 이익이 되지는 못했지만, 그래도 그런 내용들을 이해 해주고 반영한 사람에 대해서 다시금 애정과 존경의 마음이 들었다.
Read more...