Profile img

bgl gwyng

@bgl@hackers.pub · 97 following · 121 followers

GitHub
@bglgwyng

타입시스템이 충분히 좋은 언어는, 특정 함수(타입을 만족하는 프로젝트 내의 아무 함수)를 CLI 바이너리로 빌드하는 기능을 one-liner로 지원할 수 있을 것이고, 그건 아마 지원할만한 기능일 것이다.

Context: Cabal의 어떤 내부 함수를 끄집어내서 CLI 툴로 만드는데 황금같이 귀중한 내 주말을 써야했다.

5

주로 하스켈만 하는 분께 좀 유명한 JS 라이브러리의 깃헙 링크를 공유드렸는데, 스타가 10k인걸 보고는 엄청나게 훌륭한 프로젝트인가보다... 하시길래 / 20 정도로 보정을 하라고 했다.

8
4
3
3
1

@hongminhee洪 民憙 (Hong Minhee) 우선 홈화면에서 레포 찾아들어가는게 불편합니다. 제 계정의 레포면 찾아들어갈수있는데, 제가 속한 organization의 레포거나 아니면 최근에 어떤 작업을 한 남의 레포의 경우엔 organization을 변경하거나 위에 검색을 해야하잖아요. 특히 검색이 알잘딱깔센이 안되는게 불편합니다.

2
3

최근 며칠간 WAH라는 이름의 WebAssembly 인터프리터를 만들고 있다. ~와! 샌즈!~

WAH의 특징이라면 C로 작성되어 있는데 헤더 하나로 구성되어 있다는 점과, 거의 대부분의 코드를 Gemini가 짰다는 것 정도일까? (Claude Code도 좀 사용했지만 코드 생성은 Gemini가 다 했다.) Gemini가 디버깅을 시키면 답답한 게 사실이라서 최대한 프롬프트에 정보를 많이 넣고 few-shot으로 생성하게 하는 걸 목표로 했는데 생각보다 잘 되었다. 예를 들어서 한 프롬프트는 다음과 같았다. 저 문장 하나 하나가 시행착오의 결과이다.

@wah.h 에 if~else~end 명령을 구현하고, 대응되는 test_*.c 파일들이 모두 성공하도록 (또는, 해당 테스트에서 잘못된 점이 있을 경우 그 원인을) 고쳐줘. 아직 loop 관련된 코드는 처리할 필요 없고 테스트 중에 그걸 테스트하는 게 있다면 주석 처리해(지우지는 마). 컴파일과 실행은 &&로 한 번에 하도록 해. 정확한 구현 방법은 이래야 해: if~else~end에서 마지막 end는 사라지고, if는 else 직후 명령으로 이동하는 conditional jump로 재활용하며, else는 unconditional jump로 바뀌어(즉 실행기 입장에서 br과 else의 동작은 똑같아야 해! else를 아예 없애고 br로 대체할지 말지는 알아서 정해). 그러니까, if A B C else D E F end G 같은 명령이 있다면 preparsing 이후에는 if <offset to D> A B B C else <offset to G> D E F G 형태가 되어야 한다는 뜻이야. WebAssembly 명세에 따르면 if 문에는 block type이 따르는데, 이 타입을 사용해서 validation을 진행하는 것도 정확히 구현해야 해(block type이 function type (T1..Tn)->(U1..Um)이면 현재 스택에 T1..Tn 타입이 들어 있고 end 이후에는 U1..Um 타입이 들어 있어야 하고, 일반 타입 T가 들어 있다면 ()->(T)와 동일하게 취급함). block type은 validation 이후 preparsing 과정에서 사라져서 런타임에는 반영되지 않도록 해.

솔직히 너무 많이 요구하는 거 아닌가, 안되면 validation 부분을 어떻게 뺄지 고민하고 있었는데 시도 세 번만에 800줄짜리 diff가 떡하니 나오고 일단 보기에는 틀린 부분이 없어서 놀랐다. 물론 삽질도 많이 했는데 가장 많이 한 삽질은 테스트를 작성할 때 수동으로 WebAssembly 바이너리를 짜면서 바이트 숫자를 잘못 세어서 오류가 나는 거랑, 분명 WebAssembly opcode를 사용해야 하는데 자기 마음대로 코드를 정해 버린다거나 하는... 그런 우스운 상황이었다.

우습기도 하고 놀랍기도 하지만 이 코드를 내가 직접 짜지 않는 이유는 귀찮아서...라기보다는 내가 이걸로 하고 싶은 일이 따로 있고 WebAssembly 인터프리터를 만드는 게 주 목표는 아니기 때문이다. (원래 하고 싶은 일은 나중에 언급할 듯.) WebAssembly 구현이라고 하면 기술적으로 복잡해 보이지만, 내 용도에서 유래하는 몇 가지 조건(대표적으로 결정론적인 동작)을 제약으로 걸면 기술적으로 복잡하다기보다는 그냥 노가다에 가까워지기 때문에 끌리지 않는 것도 있긴 하다. 이전의 Angel이 과연 얼마까지 바이브 코딩으로 할 수 있는지를 테스트하는 목표였다면, 이번에는 정말로 목표를 달성하는 수단으로 기능할지 실험해 볼 작정이다.

https://github.com/lifthrasiir/wah/ 정식으로 공개했다. 현재 4800여줄. WebAssembly 1.0 거의 완전 지원, 2.0은 SIMD를 포함해 8~90% 정도 지원하는 정도까지 왔다. 하지만 아직 API 문제를 완전히 풀진 못해서 모듈 링킹이 안 되는 치명적인 문제가 있다...

8
2

http://logitext.mit.edu/main 재미있는 웹 앱 중 하나. 논건 대수(Sequent Calculus)를 사용해 1차 논리("모든 대상에 대해"나 "어떤 대상이 있어"를 서술할 수 있는 논리)의 명제를 상호작용을 통해 증명해 볼 수 있다. 예를 들어 A /\ B -> A (A 그리고 B이면 A이다)를 증명하려면

  • 위 명제를 입력칸에 넣는다.
  • ->를 눌러 명제 안의 "이면"을 증명에서 쓸 수 있는 가정(|-의 왼쪽에 있는 것)으로 바꾼다.
  • 가정의 A /\B를 눌러 "그리고"의 양 측에 해당하는 가정 AB 각각을 얻는다.
  • 가정이나 결론의 A를 눌러 가정을 사용하는 것으로 증명을 끝낸다.

보다 입문자에게 친절한 설명은 http://logitext.mit.edu/tutorial 에서 읽어볼 수 있다.

4

bgl gwyng shared the below article:

[잘라먹는 프로그래밍 언어론] 타입 체계는 명제 논리와 닮아있다 (커리-하워드 대응)

RanolP @ranolp@hackers.pub

이 글은 함수 타입, 합 타입, 곱 타입과 논리 연산의 대응 관계를 탐구하며, 특히 부정(negation)을 타입 시스템에서 어떻게 표현할 수 있는지에 대해 설명합니다. "P가 아니다"는 "P이면 거짓이다"와 동치라는 점을 이용하여, 타입 이론에서 값이 없음을 거짓으로 해석하고, 이를 통해 "정수를 0으로 나눌 수 없다"는 명제를 타입으로 표현하는 방법을 제시합니다. `div_by_zero :: Int -> ⊥`와 같은 표현을 통해 타입 체계와 명제 논리 간의 커리-하워드 대응을 보여주며, 타입 시스템이 논리적 추론과 어떻게 연결되는지에 대한 통찰력을 제공합니다.

Read more →
10
0
0
0
3

최근 며칠간 WAH라는 이름의 WebAssembly 인터프리터를 만들고 있다. ~와! 샌즈!~

WAH의 특징이라면 C로 작성되어 있는데 헤더 하나로 구성되어 있다는 점과, 거의 대부분의 코드를 Gemini가 짰다는 것 정도일까? (Claude Code도 좀 사용했지만 코드 생성은 Gemini가 다 했다.) Gemini가 디버깅을 시키면 답답한 게 사실이라서 최대한 프롬프트에 정보를 많이 넣고 few-shot으로 생성하게 하는 걸 목표로 했는데 생각보다 잘 되었다. 예를 들어서 한 프롬프트는 다음과 같았다. 저 문장 하나 하나가 시행착오의 결과이다.

@wah.h 에 if~else~end 명령을 구현하고, 대응되는 test_*.c 파일들이 모두 성공하도록 (또는, 해당 테스트에서 잘못된 점이 있을 경우 그 원인을) 고쳐줘. 아직 loop 관련된 코드는 처리할 필요 없고 테스트 중에 그걸 테스트하는 게 있다면 주석 처리해(지우지는 마). 컴파일과 실행은 &&로 한 번에 하도록 해. 정확한 구현 방법은 이래야 해: if~else~end에서 마지막 end는 사라지고, if는 else 직후 명령으로 이동하는 conditional jump로 재활용하며, else는 unconditional jump로 바뀌어(즉 실행기 입장에서 br과 else의 동작은 똑같아야 해! else를 아예 없애고 br로 대체할지 말지는 알아서 정해). 그러니까, if A B C else D E F end G 같은 명령이 있다면 preparsing 이후에는 if <offset to D> A B B C else <offset to G> D E F G 형태가 되어야 한다는 뜻이야. WebAssembly 명세에 따르면 if 문에는 block type이 따르는데, 이 타입을 사용해서 validation을 진행하는 것도 정확히 구현해야 해(block type이 function type (T1..Tn)->(U1..Um)이면 현재 스택에 T1..Tn 타입이 들어 있고 end 이후에는 U1..Um 타입이 들어 있어야 하고, 일반 타입 T가 들어 있다면 ()->(T)와 동일하게 취급함). block type은 validation 이후 preparsing 과정에서 사라져서 런타임에는 반영되지 않도록 해.

솔직히 너무 많이 요구하는 거 아닌가, 안되면 validation 부분을 어떻게 뺄지 고민하고 있었는데 시도 세 번만에 800줄짜리 diff가 떡하니 나오고 일단 보기에는 틀린 부분이 없어서 놀랐다. 물론 삽질도 많이 했는데 가장 많이 한 삽질은 테스트를 작성할 때 수동으로 WebAssembly 바이너리를 짜면서 바이트 숫자를 잘못 세어서 오류가 나는 거랑, 분명 WebAssembly opcode를 사용해야 하는데 자기 마음대로 코드를 정해 버린다거나 하는... 그런 우스운 상황이었다.

우습기도 하고 놀랍기도 하지만 이 코드를 내가 직접 짜지 않는 이유는 귀찮아서...라기보다는 내가 이걸로 하고 싶은 일이 따로 있고 WebAssembly 인터프리터를 만드는 게 주 목표는 아니기 때문이다. (원래 하고 싶은 일은 나중에 언급할 듯.) WebAssembly 구현이라고 하면 기술적으로 복잡해 보이지만, 내 용도에서 유래하는 몇 가지 조건(대표적으로 결정론적인 동작)을 제약으로 걸면 기술적으로 복잡하다기보다는 그냥 노가다에 가까워지기 때문에 끌리지 않는 것도 있긴 하다. 이전의 Angel이 과연 얼마까지 바이브 코딩으로 할 수 있는지를 테스트하는 목표였다면, 이번에는 정말로 목표를 달성하는 수단으로 기능할지 실험해 볼 작정이다.

9
0
5

bgl gwyng shared the below article:

내가 LLM과 함께 코딩하는 방식

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

이 글은 저자가 LLM(Large Language Model)을 활용하여 코딩하는 방법에 대한 개인적인 경험과 팁을 공유합니다. LLM 코딩 에이전트 사용 시 맥락 제공의 중요성을 강조하며, Claude Code 모델을 선호하는 이유와 그 장단점을 설명합니다. 세부적인 지시를 위해 GitHub 이슈를 활용하고, 설계는 사람이, 구현은 LLM이 담당하는 역할 분담을 제안합니다. 또한, 프로젝트 지침을 담은 *AGENTS\.md* 파일의 중요성과 Context7을 활용한 문서 제공 방법을 소개합니다. 계획 모드를 통해 LLM이 스스로 피드백 루프를 돌도록 유도하고, 필요한 경우 손 코딩을 병행하여 코딩의 재미를 유지하는 전략을 제시합니다. 이 글은 LLM을 단순한 도구가 아닌 협력적인 동료로 활용하여 개발 효율성을 높이는 방법을 모색하는 개발자들에게 유용한 인사이트를 제공합니다.

Read more →
37
0
1

이제 자신이 보여주고 싶지 않은 추천사를 가리는 기능도 추가되었습니다. 메인 페이지에서 링크 타고가시면 사용 가능해요. 많은 이용 부탁드립니다.

https://referral.akaiaoon.dev/ 이 링크에서 사용 가능하고, 내가 받은 추천사는 https://referral.akaiaoon.dev/u/:username 으로 볼 수 있습니다. 아래 말코링님의 추천사 리스트를 참조해 주세요.

말코링님의 추천사

레퍼럴프로젝트의 새로운 기능 - 추천사 가리기
8

@hongminhee洪 民憙 (Hong Minhee) @curry박준규 제가 친구 가르쳐본 경험으론요. 그냥 do notation 알려주고 알아서 하라고하니, 시간 좀 지나서 main이 어떻게 평가되는지 내가 잘 모르는거 같다? 하고 알아서 눈치를 채더라고요. 이때 알려주면 됩니다.

부리또 이슈는 본인이 뭘 모르는지도 모른는 사람을 가르치려다가 생기는거 같아요. 최소 자신이 뭔가 모른다는 사실은 스스로 깨닫게 냅둬야합니다.

3
6
6

이거 아무리 봐도 옛날에 본 심리검사 문항 같다. 이런 느낌으로

"벌려둔 일이 너무 많아서 뭐부터 해야 할지 정하질 못한 채 우왕좌왕하는 일이 많다."라는 문항에 대해 "전혀 안 그렇다"에서 "매우 그렇다"까지 다섯 단계 중 하나로 표시할 수 있는 심리검사 질문지를 그린 것
10
8

IQ 테스트로 인간을 판별하고 구분짓는것에는 불편한 느낌이 들지만(그게 쓸모없단 얘긴 아님), 그와중에 우리집 강아지 견종인 요크셔테리어가 똑똑한 견종으로 분류되는 글을 보면 진심으로 뿌듯하다...

4

https://github.com/bglgwyng/nix-x-cabal

한달간의 삽질끝에 Nix + Haskell 빌드 프레임워크를 완성했다. 늘 Nix, Haskell에 기여하고 싶었지만, 솔직히 이걸 내가 직접해야하는 상황이 올줄은 몰랐네. Nix 디버깅하느라 정말 개고통이었다..

4

bgl gwyng shared the below article:

공허한 참

박준규 @curry@hackers.pub

하스켈의 `all` 함수에 빈 리스트를 넣었을 때 왜 `True`가 반환되는지에 대한 의문을 "공허한 참(Vacuous truth)"이라는 개념을 통해 탐구합니다. 흔히 '구현이 그렇게 되어 있으니까'라고 생각할 수 있지만, 저자는 이 현상을 논리적으로 분석합니다. `all` 함수의 구현 방식과, 빈 리스트에 대한 연산 결과가 전체 결과에 미치는 영향을 설명하며, 공집합의 모든 원소가 짝수라는 명제가 참인 이유와 유사한 논리적 근거를 제시합니다. 이를 통해 코드와 수학 간의 연결고리를 발견하고, 마지막으로 ChatGPT가 생성한 유머러스한 이미지를 곁들여 독자에게 즐거움을 선사합니다.

Read more →
5
13
17
0
0

https://referral.akaiaoon.dev/

github referral 사이드 플젝을 드디어 외부공개했읍니다... 적당히 추천하시고, 본인이 받은 추천사는 https://referral.akaiaoon.dev/api/recommendations/:github_id 로 URL 링크를 거시면 대충 svg가 말려옵니다. 깃허브 프로필에도 마크다운으로 링크 가능합니다.

예: 말코링

아직 임시라 수정 요청 혹은 피드백은 환영합니다.

1
7

https://referral.akaiaoon.dev/

github referral 사이드 플젝을 드디어 외부공개했읍니다... 적당히 추천하시고, 본인이 받은 추천사는 https://referral.akaiaoon.dev/api/recommendations/:github_id 로 URL 링크를 거시면 대충 svg가 말려옵니다. 깃허브 프로필에도 마크다운으로 링크 가능합니다.

예: 말코링

아직 임시라 수정 요청 혹은 피드백은 환영합니다.

5

몇년전에 모 기업 공채를 지원했는데. 마지막 인적성 면접만 남긴 상태에서 간접적으로 그때까지의 점수를 짐작할 방법이 있었는데, 정말 99% 합격했다고 생각했다. 결국 인적성 면접보고 떨어졌는데 거기서 정말 점수를 엄청나게 까먹었단 얘기다. 근데 지금도 이유가 뭔지 모르겠다. 진짜 모든 질문에 무난~한 대답만 했는데 말이지... 그거 떨어지고 다른 회사 갔는데 거기서 커리어도 꽤 꼬여서, 종종 다시 생각하면 아쉬워진다.

3

부연설명을 하자면. Git에선 브랜치 자체로는 '변경 사항'이라는 의미가 없습니다. 왜냐면 끝점만 있고 시작점만 있으니까요. 변경 사항을 논하려면 비교 대상인 커밋이 필요합니다.

Rebase를 하는 이유는 연속된 커밋들로(예쁩니다) '변경 사항'을 나타내기 위해서입니다. 그 의도한 '변경 사항'을 만들기 위해, 비교 대상이 될 커밋을 바꾸는게 리베이스입니다. 그러니까 개발자가 의도한 diff를 그대로 표현하지 못해서, diff = head - x니까 이 방정식을 만족시키는 x 커밋을 찾아서 diff를 의도한데로 계산되게 만드는거지요.

참 뻘스럽습니다.

1

Git 떡밥이 지나갔군요. 리베이스가 왜 필요할까요? Git 브랜치에 시작점의 개념이 없기 때문입니다. 브랜치는 커밋 ref가 아니라 (시작 커밋 ref, 끝 커밋 ref)가 되어야 합니다.

3
14
1

친구 회사에서 react-form-mozard의 잠깐 언급되었는데, Generator 기반인게 문제가 되어 도입이 바로 기각되었다. yield*async, await, try, catch 등등과 달리 혐오스러운 외양을 갖고 있는게 문제가 되었다. 여러분 제발 키워드 차별을 멈춰주세요ㅠㅠ

5

bgl gwyng shared the below article:

LogTape 1.1.0: Smarter buffering, seamless integration

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

LogTape 1.1.0 introduces smarter and more flexible logging with two major features. The first is "fingers crossed" logging, which buffers debug and low-level logs in memory and only outputs them when an error occurs, providing a complete sequence of events leading up to the problem. Category isolation prevents one component's errors from flushing unrelated logs, keeping logs focused and relevant. The second feature is direct log emission via the `Logger.emit()` method, which allows feeding logs from external systems like Kafka directly into LogTape while preserving original timestamps and metadata. This release also includes bug fixes and improvements across the ecosystem, such as fixes for potential data loss during high-volume logging and improved cross-runtime compatibility. Upgrading to 1.1.0 is backward-compatible and enhances debugging in production by providing complete context for every error without constant verbose logging.

Read more →
4
1

소스코드 사이의 안정적인 하이퍼링크를 만들수 있는 기능이 없다. 가령 A.hs에서 주석을 쓰면서 B.hs의 foo란 함수의 구현의 특정 부분을 언급하고자 할때, 그냥 B.hs L:77 이렇게, 소스코드가 수정이라도 되면 바로 유효하지 않게되는 방식으로 언급할수 밖에 없다. 만약 소스 코드 어디에서든 전역적인 심볼을 자유롭게 선언할 수 있다면 이 문제를 해결할 수 있을텐데...

2
1

소스코드 사이의 안정적인 하이퍼링크를 만들수 있는 기능이 없다. 가령 A.hs에서 주석을 쓰면서 B.hs의 foo란 함수의 구현의 특정 부분을 언급하고자 할때, 그냥 B.hs L:77 이렇게, 소스코드가 수정이라도 되면 바로 유효하지 않게되는 방식으로 언급할수 밖에 없다. 만약 소스 코드 어디에서든 전역적인 심볼을 자유롭게 선언할 수 있다면 이 문제를 해결할 수 있을텐데...

3
1
4