Hy 1.0 – Python을 위한 Lisp 방언
(github.com/hylang)- Python에 내장되는 Lisp 방언인 Hy 1.0.0이 약 12년간의 간헐적 개발과 실제 사용을 거쳐 릴리스됨
- Hy 1.x에서는 문서화된 언어 요소의 호환성 깨짐이 major 버전 증가로 이어지며, CPython 개발자가 더 이상 지원하지 않는 Python 버전 지원 중단은 예외로 둠
- 향후 초점은 새 버그 수정, 새 Python 버전 호환성 추가, 기존 Hy 1.x.y 코드가 깨지지 않는 방식의 Python 신규 기능 지원에 맞춰짐
- 한 사용자는 Hy 매크로로 SQLAlchemy ORM 선언을
defmodel형태로 줄이는 예를 들며, 매크로 확장이므로 런타임 추가 비용이 없다고 설명함 - MicroPython 위에서 직접 동작하는지는 표준 라이브러리 부분집합 때문에 어려워 보이며, CPython에서
hy2py로 변환한 뒤 MicroPython이 지원하는 구성만 쓰는 방식은 가능할 수 있음
Hy 1.0.0 릴리스
- Hy 1.0.0이 릴리스됨
- Hy는 Python에 내장되는 Lisp 방언임
- 릴리스까지 거의 12년간 간헐적 개발과 많은 실제 사용이 있었음
- 소개와 문서는 Hylang.org에서 제공됨
- 버전 이력은 NEWS file에서 확인할 수 있음
- 덜 진지한 릴리스 관련 글로 HYPE POST가 함께 연결됨
1.x 호환성 정책
- 앞으로 문서화된 언어 부분의 breaking change는 major 버전 번호를 올림
- 예외는 CPython 개발자가 더 이상 지원하지 않는 Python 버전의 지원을 중단하는 경우임
- major 버전 증가가 자주 발생하지 않도록 하는 의도가 제시됨
- 향후 작업 초점은 다음에 맞춰짐
- 새로 발생하는 버그 수정
- 새 Python 버전과의 호환성 추가
- 이전 Hy 1.x.y에서 동작하는 코드를 깨지 않는 방식으로 Python 신규 기능 지원
Hy 매크로 활용 예: SQLAlchemy 모델 DSL
- 한 사용자는 Hy로 ORM과 비동기 웹 프레임워크를 만들고 있으며, 둘 다 기존 라이브러리를 활용하고 대부분 매크로로 구성된다고 설명함
- SQLAlchemy ORM Quick Start Guide의 모델 선언을 Hy의
defmodel매크로로 더 짧게 표현하는 예가 제시됨User,Address모델과 관계 선언을 Hy S-expression 형태로 작성함defmodel은 SQLAlchemy 코드로 확장되는 매크로라서 런타임 추가 비용이 없음
- 사용자는 Hy 내부와 API가 안정화된 것이 이런 작업에 필요하다고 밝힘
관계 선언과 쿼리 DSL 논의
defmodel예시는 여러 관계 패턴으로 확장됨- one-to-one:
1->1 - many-to-many:
*->*와deflinktable - timestamp 필드:
:timestamp-create,:timestamp-update
- one-to-one:
- 선언 후 객체는 일반적인 SQLAlchemy 2.0 ORM 객체이므로, 데이터베이스 스키마 DSL 부분만 Hy로 쓰고 나머지는 Python으로 쓸 수 있음
- 쿼리 DSL은 아직 작업 중이며, fluent interface가 S-expression과 잘 맞지 않는다고 언급됨
- 한 댓글은 SQL의 syntactic order와 semantic order가 맞도록 만들 것을 제안하며 Google Research의 SQL Has Problems. We Can Fix Them: Pipe Syntax In SQL을 연결함
- 이에 대해
|>같은 형태나 list comprehension을 흉내 내는 방식이 가능할 수 있지만, 최종 설계는 작은 앱을 만들고 리팩터링하는 반복 뒤에 나올 것이라고 답함
MicroPython 가능성과 릴리스 반응
- MicroPython 위에서 CPython 대신 동작할 수 있는지에 대한 질문이 나옴
- 답변은 MicroPython이 Python 표준 라이브러리의 작은 부분집합만 포함하므로 직접 동작은 어려워 보인다는 쪽임
- 다만 CPython에서
hy2py를 사용해 Python 코드로 변환한 뒤, MicroPython이 지원하는 구성으로 제한하면 출력물을 실행할 수 있을 수 있음 - 릴리스 당일 Hylang.org를 호스팅하는 웹 서버의 일일 고유 방문자 수가 크게 증가한 것이 확인됨
댓글과 토론
Hacker News 의견들
-
Hy가 실제로 Python으로 어떻게 변환되는지 파악하기가 좀 어려웠고, 컴파일되는지 인터프리트되는지도 처음엔 확신이 없었음
결국 Wikipedia에서 “Hy는 s-expression을 Python의 추상 구문 트리(AST) 로 변환해 Python과 상호작용하도록 설계된 Lisp 방언”이라는 설명을 찾았고, GitHub 코드를 보면 컴파일러도 Python으로 작성된 듯함: https://github.com/hylang/hy/blob/master/hy/compiler.py
메인 사이트에서도 “Python에 임베드된 Lisp 방언”보다는 “Python AST로 컴파일되는 Lisp 방언”이라고 소개하면 더 명확할 것 같음. Lisp를 임베드하는 방식은 인터프리터를 붙이거나, Python 바이트코드로 컴파일하거나, Python 소스 코드로 변환하는 등 여러 가지이고 각각의 절충점이 꽤 다름- README/GitHub 페이지에는 이미 “Hy는 Python에 임베드된 Lisp 방언이며, Lisp 코드를 Python AST 객체로 변환하므로 Python 세계를 Lisp 형태로 쓸 수 있다”고 되어 있음
- 맞음, 이 컴파일러는 Python으로 작성되어 있고 Hy는 셀프 호스팅이 아님
보통 Hy 소스 코드는 Python AST 객체가 되고, Python이 이를 컴파일해 실행함. 다만 Python AST 객체를 Python 소스 텍스트로 바꾸는 것도 가능하고, Hy에서 Python을 쓰거나 Python에서 Hy를 쓰는 상호 운용도 가능함: https://hylang.org/hy/doc/v1.0.0/interop - “임베드”라는 표현은 한 프로젝트 안에서 Python과 Hy를 섞고 양방향 호출할 수 있다는 데서 나온 것임
결국 모두 Python 바이트코드가 되기 때문에 잘 동작함 - 원래 Hy 발표에서는 Lisp를 Python 바이트코드로 컴파일해 임베드한다는 점이 분명히 나옴
아래 영상의 16:25쯤에서 볼 수 있음: https://m.youtube.com/watch?v=1vui-LupKJI
-
Hy가 수년간 성숙하면서 더 Lispy하고 덜 Pythony해지도록 문법 설탕과 특수 사례를 쌓기보다는, 오히려 Python 기능 집합의 얇은 문법 추상화에 가까워진 듯함
즉 다른 방식으로 흉내 내기 어려운 핵심, 특히 매크로에 집중하는 방향임. 최근 예로match는 그냥 Python의 네이티브match이고 Python 3.10 이전 버전을 위한 폴리필도 없음. 예전에는foo?가 특수 사례로is_foo로 맹글링됐지만 제거됐고,hy.eval은 Python의eval에 더 가깝게 개편됐으며,unless같은 있으면 좋은 비핵심 유틸리티는 Hyrule 패키지로 자주 밀려남
처음엔 직관에 반하는 방향처럼 느껴졌지만, Python에서 Hy로 넘어올 때 학습 곡선을 줄이고 Python 패키지와 일관되게 상호작용하기 쉬워진다는 장점이 큼. 어쩌면 언어 유지보수를 단순화하려는 이유도 있을 것 같고, 기억상let도 제대로 만들기까지 네 번쯤 시도했던 듯함- 어느 순간 Python과의 불필요한 차이를 최소화하면 언어 유지보수와 사용이 모두 훨씬 매끄러워진다는 걸 깨달았음
Hy 코드를 쓸 때도 Hy 문서보다 Python이나 서드파티 Python 라이브러리 문서를 훨씬 더 자주 보게 됨. Python을 개선할 수 있는 지점은 여러 가지라고 느꼈지만, 예전처럼 Clojure를 배려해True를true로 쓸 수 있게 한 기능은 그냥 불필요한 복잡성이었음
- 어느 순간 Python과의 불필요한 차이를 최소화하면 언어 유지보수와 사용이 모두 훨씬 매끄러워진다는 걸 깨달았음
-
HYPE POST가 정말 좋았음. 기업용 소프트웨어 일을 하는 입장에서 풍자 감각이 아주 뛰어남
https://github.com/hylang/hy/discussions/2609 -
드디어 나왔으니 이제 https://github.com/rcarmo/sushy를 정리할 수 있겠음
몇 년간 조금씩 만져 왔지만, Hy를 업그레이드할 때마다 문법 일부가 깨지거나 기능이 Hyrule 패키지로 들어갔다 나왔다 해서 곤란했음
참고로 Hy는 iPad의 https://holzschu.github.io/a-Shell_iOS 안에서도 꽤 잘 동작함. 다만 vim/neovim의 구문 강조는 0.29+ 릴리스와 비동기를 따라잡아야 함
그동안 Fennel과 Guile도 써 봤지만, Python 라이브러리와 생태계에 접근할 수 있는 쪽이 더 좋음. 비동기 덕분에 효율적인 API 작업도 잘할 수 있고, 여러 Scheme에서는 소켓 재사용과 헤더를 세밀하게 제어하며 HTTPS를 다루는 일이 여전히 번거로워서 aiohttp를 쓰는 편이 훨씬 낫다고 봄 -
초기의 소박한 시작점과 비교하면 정말 멀리 왔음
예전에 PyCon에서 Hy를 처음 세상에 소개한 라이트닝 토크를 봤고, 얼마 지나지 않아 Paul을 만나 초기 Hy 버전에 기여하기 시작했음. Common Lisp 스타일의kwargs, 내부 일부, 라이브러리 한두 개를 맡았음
장난기는 유용하고, 특히 열정을 유지하는 데 도움이 됨. 해커가 해커답게 굴 수 있고 모든 것이 비즈니스일 필요는 없다는 점이 좋음. 몇 년째 관여하지 않았지만 프로젝트가 계속 나아가는 걸 보니 기분이 좋고, 훌륭한 이정표라고 느껴짐 -
Clojure 팬이라면 관련해서 Python 3.8+를 대상으로 하는 Clojure 호환에 가까운 Lisp 방언 Basilisp도 있음
https://github.com/basilisp-lang/basilisp -
Lisp는 아니지만, Python으로 트랜스파일되는 함수형 프로그래밍 언어라는 관점에서는 Coconut도 흥미로움: https://coconut-lang.org/
Hy나 Coconut을 실제로 써 본 사람들의 경험담이 정말 궁금함- 몇 년 전에 Coconut을 조금 써 봤는데, 당시 인상은 컴파일러가 유용할 만큼 똑똑하지 않다는 쪽이었음
생성된 코드 맨 위에 하드코딩된 보조 함수가 잔뜩 붙었고, 같은 내용을 평범한 Python으로 쓴 것보다 프로그램이 훨씬 느렸음
반대로 Hy는let의 스코프 처리에서 생기는 약간의 간접 계층이나 반환값 주변의 차이를 빼면, 사람이 손으로 쓸 법한 Python 코드와 꽤 가까운 코드를 생성함. 다만 Coconut도 시간이 오래 지났으니 개선됐을 수 있음
- 몇 년 전에 Coconut을 조금 써 봤는데, 당시 인상은 컴파일러가 유용할 만큼 똑똑하지 않다는 쪽이었음
-
축하함. 두 가지가 궁금함: REPL 주도 개발을 지원하는지, 예를 들어 조건 시스템이나 breakloop 같은 것이 있는지 궁금함
또 독립 실행 배포판이 있는지도 궁금함. Python 배포 자체가 번거롭기 때문에, 이상적으로는 모든 의존성을 포함한 단일 Hy 바이너리 하나를 배포할 수 있으면 좋겠음. 정적 링크든 임시 디렉터리에 푸는 zip 파일이든 괜찮음- 독립 실행 배포판은 아니지만
uvx hy@1.0.0로 Hy REPL에 들어갈 수 있음
echo '(print "hi hn")' > hi.hy다음에uvx hy@1.0.0 hi.hy를 실행하면"hi hn"을 출력함
https://docs.astral.sh/uv/guides/tools/#running-tools
참고로 uv는 Python 버전 설치와 관리도 할 수 있음 - breakloop가 무엇인지는 잘 모르겠음. Hy는 Python의 예외 시스템을 사용하고, 이는 Common Lisp의 조건 시스템보다는 전통적인 예외 시스템에 더 가까움
독립 실행 배포판은 없음 - REPL 문서에 관련 내용이 있음: https://hylang.org/hy/doc/v1.0.0/repl
코드를 대화식으로 디버깅하려면 디버깅하려는 코드에(.run (hy.REPL :locals {#\* (globals) #\* (locals)}))를 넣을 수 있고, Python에서는import hy; hy.REPL(locals = {\*globals(), \*locals()}).run()처럼 쓸 수 있음
다만code.interact()와 마찬가지로, REPL 안에서 지역 변수를 바꿔도 원래 스코프로 전파되지는 않음 py2app와 신중한 해킹으로 2번에 가까운 건 해 본 적 있음
전부 바이트코드로 컴파일한 뒤 Python의 단일 파일 배포 도구를 사용할 수 있음- Hy는 Python이 지원하는 기능 집합을 그대로 지원함. 전통적인 단계별 디버깅이나 사후 디버깅에는 꽤 좋고, CPython에는 더 고급의 내부 훅도 많이 있음
하지만 조건 시스템이나 handlers/restarts 같은 것은 없음
- 독립 실행 배포판은 아니지만
-
덜 진지한 부분이 아주 좋았음. 더 많은 프로그래밍 프로젝트가 기발함을 받아들였으면 좋겠음
어쩌면 그게 Python 전통을 기리는 가장 좋은 방식일 수도 있음- 몇 년 전에는 Hy와 문서에서 장난기 있는 요소를 많이 없앴음. 산만했고 시끄러운 테스트 실패를 만들었기 때문임
다만 어느 순간 너무 멀리 갔다는 생각이 들어서, 최근에는 장난기를 조금 다시 넣으려 하고 있음
- 몇 년 전에는 Hy와 문서에서 장난기 있는 요소를 많이 없앴음. 산만했고 시끄러운 테스트 실패를 만들었기 때문임
-
Hy를 간헐적으로 써 왔고, transformer를 만들어 보려 하다가 Hy로 작성한 https://github.com/kunalb/orphism도 공개했음
이제 다시 꺼내서 제대로 돌려볼 때가 된 것 같음