
Jacquard: '이 코드가 무엇을 건드릴 수 있는가?'라는 질문이 한 줄로 해결되는 언어
요약
Jacquard는 코드가 시스템에 미치는 영향(Effect)을 타입 시스템에 명시하여 보안과 예측 가능성을 높이는 연구용 프로그래밍 언어입니다. 네트워크, 파일 접근 등의 효과를 타입에 포함하고 컴파일러와 런타임이 이를 강제함으로써 코드의 의도를 명확히 합니다.
핵심 포인트
- 효과(Effects)를 타입 시스템 내에 통합하여 코드의 영향력을 명시함
- 컴파일러와 런타임이 허용되지 않은 효과를 물리적으로 차단
- AI가 작성한 코드의 안전성을 검증하는 데 유용한 접근 방식 제공
- 단일 바이너리 설치로 간편한 실행 환경 지원
저는 코드를 작성하기도 하고, 다른 사람들(그리고 모델들)이 작성한 코드를 읽기도 합니다. 제 하루를 잡아먹는 것은 타이핑이 아닙니다. 바로 _'이 코드가 실제로 무엇을 건드릴 수 있는가, 그리고 나는 그것을 얼마나 확신하는가?'_라는 질문에 답하는 일입니다. Jacquard는 그 답을 첫 번째 줄에 명시하고, 컴파일러(compiler)가 이를 정직하게 유지하도록 강제하는 제가 본 첫 번째 언어입니다.
대부분의 언어는 함수가 무엇을 계산하는지 알려줍니다. 하지만 그것이 세상에 어떤 영향을 미치는지(what it does to the world) 알려주는 언어는 거의 없습니다. 제가 리뷰하는 코드 중 점점 더 많은 비중을 제가 알지 못하는 모델이 작성한 코드가 차지하는 시대에, 그 간극이 바로 제 시간을 낭비하게 만듭니다. 무해해 보이는 normalize_name 함수가 네트워크에 접근하는지 확인하기 위해 두 단계 아래에 있는 lookup_alias를 추적하는 일 말입니다.
Jacquard는 그 반대의 도박을 거는 작은 연구용 언어(작성 시점 기준 v0.1 rc3)입니다. 효과(Effects) — 네트워크, 파일, 시계, 무작위성(randomness) — 가 타입(type) 안에 살아있습니다. 체커(checker)는 이를 숨기는 시그니처(signatures)를 거부합니다. 런타임(runtime)은 CLI가 허용하지 않은 효과를 거부합니다. 이 포스트는 제가 실제로 실행해 본 부분들을 직접 살펴보는 과정입니다.
5분 설치법
설치 스크립트는 단일 바이너리(binary)와 데모 트리(demo tree)를 내려받습니다. OCaml도, opam도 필요 없습니다.
curl -fsSL https://raw.githubusercontent.com/jbwinters/jacquard-lang/jacquard-core-0.1-rc3/scripts/install.sh | sh
~/.local/bin/jac run ~/.local/share/jacquard/demos/basics/m1-fact.jac
# 120
만약 120이 출력된다면, 이 언어가 당신의 머신에 설치된 것이며 함께 따라오실 수 있습니다.
안녕, 권한 부여(capability grant)
여기에 볼 가치가 있는 첫 번째 내용이 있습니다. 사소한 프로그램은 문자열을 출력합니다. 약간 덜 사소한 프로그램은 네트워크를 건드리려 합니다. 그리고 Jacquard의 런타임은 제가 별도로 지시하기 전까지는 물리적으로 그것을 허용하지 않습니다.

두 번째 파일의 코드는 다음과 같습니다:
net-sample : (Text) ->{Net} Text
net-sample(url) = match fetch(MkRequest(url, "")) {
| MkResponse(_, body) -> body
...
주의 깊게 봐야 할 두 가지가 있습니다. 시그니처 (Text) ->{Net} Text는 이 함수가 Net 효과 (effect)를 수행할 수 있음을 명시합니다. 이 줄은 주석이 아닙니다. 체커 (checker)가 호출 그래프 (call graph)로부터 이를 계산하며, 본문에서 수행하는 효과를 누락한 시그니처는 모두 거부합니다. 또한 런타임 (run time) 시에 --allow net 옵션이 없다면, 단 하나의 패킷도 기기를 떠나기 전에 프로그램은 명시적인 에러와 함께 중단됩니다:
error[E0814]: this program requires the `net` effect, which is not granted
hint: grant it with --allow net, or handle the effect in the program
종료 코드 (Exit code) 3. --allow net을 추가하면 실행됩니다. 이것이 모델의 전부입니다. 타입 (type)이 말하는 바를 런타임 (runtime)이 강제합니다. 그리고 이는 동적으로 로드된 코드 (dynamically loaded code)에 대해서도 강제되는데, 바로 이 지점이 대부분의 언어가 주장하는 "효과에 대한 검토 (reviewed for effects)"라는 이야기가 조용히 무너지는 지점입니다.
저에게 있어 이것은 이 언어에서 가장 흥미로운 단 한 가지 요소입니다. 생성된 코드를 훑어볼 때 제가 던지는 첫 번째 질문은 "이 코드가 무엇을 건드릴 수 있는가?"입니다. Jacquard에서는 그 답이 첫 번째 줄에 있으며, 저는 그것이 정직하다고 믿을 필요가 없습니다. 컴파일러 (compiler)가 이미 확인했기 때문입니다.
세 가지 세계에서의 동일한 정책
설치 파일은 두 번째 핵심 아이디어를 보여주는 출시 위험 사례 연구 (release-risk case study)를 포함하고 있습니다. 즉, 한 번 작성된 프로그램이 서로 다른 질문에 답하기 위해 서로 다른 핸들러 (handlers) 하에서 실행된다는 점입니다.
도메인은 의도적으로 평범합니다: inventory (재고)와 payments (결제)의 상태, 그리고 에러 급증 여부를 바탕으로 Ship (배송), Canary(percent) (카나리 배포), 또는 Hold(reason) (보류)를 결정합니다. 특이한 점은 이 하나의 정책이 얼마나 다양한 종류의 질문에 답할 수 있느냐 하는 것입니다:
- 구체적인 스냅샷 (Concrete snapshot).
with-snapshot(Healthy, Degraded, False, ...)는 텔레메트리 (telemetry) 효과를 특정 값으로 고정하고 하나의 결정인canary(5)를 반환합니다. - 확률적 세계 (Probabilistic world).
with-risk-model은 동일한Telemetry연산을Dist(분포)로부터 추출된 샘플로 재해석하고, 관찰된 체크아웃 실패를 조건으로 하여 사후 확률 (posterior)을 열거합니다:
0.305077 canary(5)
0.295394 hold("inventory-down")
0.184621 canary(10)
...
0.059005 ship은 비교를 위한 임계값이 아닙니다. 이는 관찰된 실패가 주어졌을 때, 이 정책이 배포(ship)를 선택할 사후 확률 (posterior probability)입니다. 일반적인 핸들러 (handler)에 의해 처리되는 일반적인 효과 연산 (observe)으로 표현된 베이지안 증거 (Bayesian evidence)입니다.
- 철저한 증명 (Exhaustive proof). 테스트 프레임워크인 Warp는 18개의 모든 텔레메트리 (telemetry) 세계에 대해 동일한 정책을 다시 실행하며, 의존성이
Down상태일 때ship이 결코 선택되지 않음을 확인합니다. 샘플링이 아니라, 열거 (enumeration)를 통한 확인입니다.
스크린샷 상단의 inferred authority (추론된 권한) 블록을 확대해 보세요:
release-assessment : () ->{Telemetry} Assessment
with-snapshot : forall a | e. (Health, Health, Bool, () ->{Telemetry | e} a) ->{| e} a
with-risk-model : forall a | e. (() ->{Dist, Telemetry | e} a) ->{Dist | e} a
...
행을 따라가 보십시오. release-assessment는 Telemetry를 요구합니다. with-risk-model은 Telemetry를 소비하여 Dist로 변환합니다. conditioned-release-risk는 권한(authority) 내에 오직 Dist만을 가지고 나옵니다. 코드 조각이 요구하는 효과와 호출자가 해소하는 효과로 이어지는 이 흐름은 여백에 적힌 주석이 아닙니다. 그것이 바로 언어입니다.
저는 이전에 Python으로 확률 모델을 작성한 적이 있습니다. 항상 동기화가 어긋나는 부분은 정책 (policy), 테스트를 위한 모의 객체 (mock), 그리고 'what-if' 분석을 위한 확률적 버전이었습니다. Jacquard에서는 이들이 서로 다른 핸들러 (handler)를 상위에 둔 동일한 100줄의 코드입니다.
코드가 모델에 의해 작성되었을 때 이것이 중요한 이유
저는 AI 안전 (AI-safety) 연구자가 아닙니다. 저는 매주 제가 작성하지 않은 코드를 읽으며 실제 시간을 보내는 사람입니다. 제가 사용해 온 모든 언어는 효과 (effects)를 호출 그래프 (call graph)의 창발적 속성 (emergent property)으로 취급합니다. 즉, 리뷰 시점에 정의를 추적하며 추론해야 하는 무언가라는 뜻입니다. 그것만으로도 이미 비용이 많이 드는 습관이었습니다. 익숙하지 않은 코드의 양이 늘어나면, 이는 감당할 수 없는 비용이 됩니다.
Jacquard의 가설은 리뷰의 적절한 단위는 시그니처 (signature)이며, 그 시그니처가 이미 당신에게 진실을 말해주어야 한다는 것입니다. 이에 따라 두 가지 결과가 뒤따르며, 위 실행 사례 모두에서 나타났습니다:
- 프롬프트 인젝션 (Prompt-injection) 스타일의 공격이 가장 선호하는 은신처를 잃습니다. 헬퍼 (helper)에 의해 호출되는 또 다른 헬퍼 내부의 숨겨진
requests.post는, 진입점 (entry point)까지 거슬러 올라가는 호출자의 효과 행 (effect row)에 나타나지 않고서는 존재할 수 없습니다. 만약 진입점이--allow net옵션 없이 실행된다면, 페이로드 (payload)가 트리거되기 전에 프로세스 실행이 거부됩니다. - "동일한 코드, 다른 환경"이 일상적인 일이 됩니다. 모킹 라이브러리 (Mock libraries), 속성 기반 테스트 (property-based tests), 그리고 확률적 가상 실행 (probabilistic what-if runs)은 모두 하나의 정책 (policy)에 대한 핸들러 (handler) 변형일 뿐입니다. 동기화해야 할 것이 아무것도 없습니다.
설계 계보가 명확합니다: Koka로부터의 효과 행 (effect rows)과 핸들러 규율 (handler discipline), Unison으로부터의 콘텐츠 주소 지정 식별자 (content-addressed identity)와 사이클 해싱 (cycle hashing), Racket으로부터의 위생 (hygiene), 그리고 Haskell으로부터의 -fno-lazy에 대한 직관입니다. 이는 바퀴를 새로 발명한 것이 아니라, 세심한 합성 (synthesis)으로 읽힙니다.
(아직은) 무엇이 아닌가
제가 실행해 본 것에 대해 솔직해지고 싶습니다:
- v0.1 rc3는 연구용 프로토타입 (research prototype)입니다. 저장소(repo)에는
docs/release/0.1/LIMITS.md파일이 포함되어 있으며, 저는 이것을 프로덕션 (production) 환경에 배포하기 전에 해당 문서의 내용을 신뢰할 것입니다. - 생태계는 단일 저장소 (one repository)로 구성되어 있습니다. 제3자 패키지 (third-party package) 관련 기능은 없습니다.
- 작은 구문론적 주의 사항 (syntactic gotchas)이 존재합니다 (제가 처음 Warp 테스트를 실행했을 때, 실수로 도입한
throw효과 (effect)를 잡아내지 못해 실패했습니다). 에러 메시지는 명확했으며, 해결 방법은throw.catch로 합성 (compose)하는 것이었습니다. 사소한 불편함 (papercut) 정도는 아니지만, 학습 곡선 (learning curve)이 아예 없는 것도 아닙니다. - 설치 스크립트에는 외부 DNS 접근이 필요합니다. DNS를 차단하는 샌드박스 (sandboxes) 환경에서는 미리 가져온 타르볼 (tarball)이 필요할 것입니다.
이 중 어느 것도 아이디어의 본질을 바꾸지는 않습니다. 다만 제가 오늘날 이 기술을 어디까지 활용할 수 있는지에 대한 한계를 설정할 뿐입니다.
10분 안에 시도해보기
위의 주장들을 본인의 환경에서 직접 확인해보고 싶다면:
# install
curl -fsSL https://raw.githubusercontent.com/jbwinters/jacquard-lang/jacquard-core-0.1-rc3/scripts/install.sh | sh
...
마지막 명령어를 실행하면 어떤 머신에서든 위의 스크린샷이 생성됩니다. 이것이 이 포스트의 핵심입니다. 제가 설명한 것 중 어느 것도 단순한 주장이 아니라, 실제 실행 결과라는 점입니다.
요약 버전
모델이 작성한 코드를 검토한다면, 여러분이 가장 먼저 묻게 되는 질문은 "이 코드가 무엇을 건드릴 수 있는가?"일 것입니다. Jacquard는 그 질문에 대한 답이 시그니처 (signature)에 담겨 있고, 런타임 (runtime)에 의해 양방향으로 강제되는 첫 번째 언어입니다. 아직 초기 단계이고 규모는 작지만, 하룻밤 정도 투자할 가치가 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기