Profile img

Hi, I'm who's behind Fedify, Hollo, BotKit, and this website, Hackers' Pub! My main account is at @hongminhee洪 民憙 (Hong Minhee).

Fedify, Hollo, BotKit, 그리고 보고 계신 이 사이트 Hackers' Pub을 만들고 있습니다. 제 메인 계정은: @hongminhee洪 民憙 (Hong Minhee).

FedifyHolloBotKit、そしてこのサイト、Hackers' Pubを作っています。私のメインアカウントは「@hongminhee洪 民憙 (Hong Minhee)」に。

Website
hongminhee.org
GitHub
@dahlia
Hollo
@hongminhee@hollo.social
DEV
@hongminhee
velog
@hongminhee
Qiita
@hongminhee
Zenn
@hongminhee
Matrix
@hongminhee:matrix.org
X
@hongminhee

I've recently been working on Optique, a CLI parser combinator for TypeScript. Optique allows you to describe complex CLIs by combining smaller parts. You can also handle the CLI parsing results in a type-safe manner (see code below). The idea came from Haskell's optparse-applicative, but since TypeScript's API style is so different from Haskell's, I referenced Zod and similar libraries for the API design. For a more detailed introduction, please refer to the article I posted on Hackers' Pub!

const parser = or(
  object({
    type: constant("network"),
    host: option(
      "-h", "--host",
      string({ metavar: "HOST" }),
    ),
    port: option(
      "-p", "--port",
      integer({ metavar: "PORT", min: 0, max: 65535 }),
    ),
  }),
  object({
    type: constant("local"),
    file: option(
      "-s", "--socket-file",
      string({ metavar: "FILE" }),
    ),
  }),
)

type Result = InferValue<typeof parser>;

// The above type is inferred as:
type Result = {
    readonly type: "network";
    readonly host: string;
    readonly port: number;
} | {
    readonly type: "local";
    readonly file: string;
}

最近、OptiqueというTypeScript向けのCLIパーサー「コンビネーター」を作っています。Optiqueは、複雑なCLIを小さなパーツの組み合わせで記述できる様にしてくれます。そして、そのCLIのパース結果を型安全に扱う事が出来ます。(下記のコード参照)アイデアはHaskellのoptparse-applicative から得ましたが、TypeScriptはHaskellとAPIのスタイルがかなり異なる為、APIの面ではZod等を参考にしました。詳しい紹介はHackers' Pubに投稿した記事をご覧ください!

const parser = or(
  object({
    type: constant("network"),
    host: option(
      "-h", "--host",
      string({ metavar: "HOST" }),
    ),
    port: option(
      "-p", "--port",
      integer({ metavar: "PORT", min: 0, max: 65535 }),
    ),
  }),
  object({
    type: constant("local"),
    file: option(
      "-s", "--socket-file",
      string({ metavar: "FILE" }),
    ),
  }),
)

type Result = InferValue<typeof parser>;

// Resultの推論された型
type Result = {
    readonly type: "network";
    readonly host: string;
    readonly port: number;
} | {
    readonly type: "local";
    readonly file: string;
}
0

I've recently been working on Optique, a CLI parser combinator for TypeScript. Optique allows you to describe complex CLIs by combining smaller parts. You can also handle the CLI parsing results in a type-safe manner (see code below). The idea came from Haskell's optparse-applicative, but since TypeScript's API style is so different from Haskell's, I referenced Zod and similar libraries for the API design. For a more detailed introduction, please refer to the article I posted on Hackers' Pub!

const parser = or(
  object({
    type: constant("network"),
    host: option(
      "-h", "--host",
      string({ metavar: "HOST" }),
    ),
    port: option(
      "-p", "--port",
      integer({ metavar: "PORT", min: 0, max: 65535 }),
    ),
  }),
  object({
    type: constant("local"),
    file: option(
      "-s", "--socket-file",
      string({ metavar: "FILE" }),
    ),
  }),
)

type Result = InferValue<typeof parser>;

// The above type is inferred as:
type Result = {
    readonly type: "network";
    readonly host: string;
    readonly port: number;
} | {
    readonly type: "local";
    readonly file: string;
}
3
2

mcp에 툴을 계속 쥐어주는게 불만이다. 불안하지도 않나? 아니 pg를 관리하는 mcp를 쓰는것보다 pg를 관리하는데 사용되는 명령어를 물어보고 그걸 내가 확인 후 실행하는게 맞지 않나? deno로 권한 다 뺏고서 mcp를 실행하면 좀 방지가 되려나?

3

러스트의 ICE 관련 이슈는 파보면 확실히 난이도가 높다. 이번에 본건 조기 종료 때문에 에러가 전파되지 않는 것이 문제인 줄 알았는데, Higher-Rank Trait Bound와 concrete 타입 간의 불일치를 처리하지 못해서 equality 검사를 하기 직전에 뻗는 것이였음.

4

박준규 replied to the below article:

Optique: 타입 안전한 CLI 파서 컴비네이터

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

이 글에서는 Haskell의 `optparse-applicative`와 TypeScript의 Zod에서 영감을 받아 제작된 새로운 CLI 파서 라이브러리인 Optique를 소개합니다. Optique는 파서 컴비네이터를 활용하여 CLI의 구조를 레고 블록처럼 조립할 수 있게 해줍니다. `option()`, `optional()`, `multiple()`, `or()`, `object()`, `constant()`, `command()`, `argument()` 등의 다양한 파서와 컴비네이터를 통해 복잡한 CLI 구조를 유연하게 정의할 수 있습니다. 특히, `or()`와 `object()` 컴비네이터를 사용하여 상호 배타적인 옵션이나 서브커맨드를 쉽게 구현하는 방법을 예제를 통해 설명합니다. Optique는 단순한 CLI 파서 역할에 집중하고 있어 모든 기능을 제공하지는 않지만, 복잡한 CLI 구조를 표현하는 데 유용하며, 소개 문서와 튜토리얼을 통해 더 자세한 내용을 확인할 수 있습니다.

Read more →
13
2
2
3

맥 미니가 자꾸 혼자 슬립 상태로 들어가길래 쓰고 있던 카페인의 문제인가 싶어서 지우고 keepingyouawake를 설치했는데 잘 될지 모르겠네...

사실 홈 서버는 맥 미니가 아니고 딴 거긴 한데 곧 얘를 중심으로 클러스터?를 만들어봐야 할 것 같기도..

2
2

洪 民憙 (Hong Minhee) shared the below article:

Par 언어 테스트 프레임워크 구현 -- Iterative Box Choice 패턴 적용

notJoon @joonnot@hackers.pub

Par 언어에 테스트 프레임워크를 구현하면서 `box choice` 타입의 소비 동작으로 인해 하나의 테스트 함수에서 여러 assertion을 처리하는 데 어려움을 겪었습니다. 기존 `box choice` 타입은 값을 한 번 사용하면 소비되어 재사용이 불가능했기 때문입니다. 이를 해결하기 위해 `iterative box choice` 타입을 도입하여 반복적인 사용이 가능하도록 개선했습니다. `iterative box choice` 타입은 `iterative`, `box`, `choice` 타입들을 조합하여 여러 번 사용 가능하고, 메서드 선택을 제공하며, 외부 구현과 연동할 수 있는 장점을 제공합니다. 새로운 타입 구조에 맞춰 테스트 실행 함수를 재귀적으로 수정하여 메서드 체이닝 방식과 순차적 명령문 방식 모두를 지원할 수 있게 되었습니다. 이로써 Par 언어는 더욱 유연하고 강력한 테스트 환경을 제공할 수 있게 되었습니다.

Read more →
4

내가 어쩌다가 이런 짓을 하게 되었나 타임라인을 정리하자면...

문제 파악

  1. 내가 만들고 있는 NestJS 앱에 fedify/nestjs 설치하고, FedifyModule 세팅해놓은 이후에 POST 요청 자체가 안 가고 있었음
  2. 왜 에러가 발생하나하고 들여다봤더니 TypeError: Response body object should not be disturbed or locked 이런 에러가 떴음.
  3. 오류가 발생한 위치는 fedify/express에서 코드 복붙할때 들어갔던 fromERequest 함수 호출 부분 이었음.
  4. 혹시나 하고, 비슷한 이슈가 있나하고 찾아봤는데 Fedify 279번 이슈에도 딱 내가 밟고 있는거랑 똑같은 에러메시지를 내뱉고 있었음.
  5. 이런 에러가 왜 발생했는지, 여기저기 찾아봤는데 hono에서도 비슷한 오류가 있었고 그걸 해결한 사례를 발견. 요약하자면, request의 body를 두번 읽으려고 해서 생긴 문제. req에 rawBody가 들어있으면 rawBody를 ReadableStream에 넣는 것으로 분기처리하고, 아니라면 기존의 코드(Readable.toWeb(req)) 그대로 사용하는 것.

해결 시도

  1. 도커 이미지 내부에는 에디터가 설치가 되어 있지 않음. 그래서, Dockerfile.dev 파일에 vim 의존성을 먼저 깔아둠
  2. vim 설치 후에는 docker compose exec app /bin/bash 커맨드로 도커 컨테이너 안쪽으로 들어가서, hono에서 하던 방식대로 시도하려고 했으나.... console.log 로 까보니 rawBody는 없고, 이미 파싱이 되어 있는 body만 남아있었음. -> 여기서 알게 된 점은.... "다른 미들웨어에 통과시키기도 전에 request에 있는 rawBody는 이미 읽혀져있구나..."
  3. NestJS의 소스코드를 까보긴 해야겠지만, 다시 돌아와서 여기Readable.toWeb(req)req.body로 바꾸니까 기적같이 그냥 돌아감...

NestJS 분석글... 쓰긴 해야겠지...? 근데, PR에도 올리긴 해야겠는데 어떡하지.... "이렇게 고치니까 되더라!!"는 좀 아닌 것 같다.

4
1
4

AI 기술이 발달하면서 글이나 코드 같은건 프롬프트를 잘 던지면 굉장히 그럴싸한 결과물을 내놔서 세상이 많이 좋아졌다고 느끼는데 디자인에선 아직 잘 모르겠다. 디자인이라해도 웹이나 앱 같은 경우엔 https://www.layermate.ai/ 같이 꽤 괜찮은 도구들이 있는데 포스터 같은걸 만들면서 나는 클립아트 정도만 AI의 도움을 (그것도 몇 번이나 삽질을 해서...) 받았다.

도둑놈 심보라는 것은 알고 있지만 포스터 같은걸 만들 때도 쓸 수 있는 저런 Layermate같은 도구가 있었으면 좋겠다는 생각을 무척이나 했다. "색상은 ..., ...를 주로 활용한 A4 사이즈 포스터를 만들어줘. 안에 이미지로는 어떠한 것들이 들어가야하고, 텍스트로는 어떤 것들이 들어가야 해." 같이 프롬프트를 잘 적으면 괜찮은 포스터 시안 몇 개가 뚝딱 나오면 세상이 오죽 편할까...

1
2
2
1
6
6

블로깅의 쇠퇴, AI의 끝없는 학습, 비공개 플랫폼(Discord 등)으로의 이주, 짧고 중독성만을 강조하는 피드와 BM, 한 번 보면 다시 찾기도 힘든 SNS 포스트, 범람하는 가짜뉴스와 개소리와 혐오... 웹은 정보의 망망대해도 아닌 소행성대로 변해가고 있다.

9
0
0

오늘 박사과정 때 쓰던 연구실을 빼러 아내와 함께 송도에 왔다. 수많은 나의 책들을 보며 이런 것도 저런 것도 공부하고 싶어 했던 예전의 내가 떠올랐다. 지금은 공부도 재밌긴 한데, 진짜 임팩트를 줄 수 있는 소프트웨어를 만들고 싶다. 병원 내에 그런 소프트웨어를 쫙 깔아보는게 내년까지의 목표!

3
6
1
2
3

CV 겸 개인 홈페이지였던 사이트를 아예 커스텀 블로그로 바꾸면서... 어제 슬쩍 홍보를 올렸는데요

https://theeluwin.github.io/

Pelican으로 만들고 GitHub Pages로 배포를 했는데, 급하게 수정할게 있어서 추가 commit을 했더니 갑자기 README를 기반으로 한 디폴트 페이지로 바뀌었습니다;;;

그러니까 기존 배포 A, 리뉴얼 배포 B, hot-fix 배포 C 이렇게 세개가 있으면, C를 했는데 실패해서 (실패 원인: GitHub Action이 새벽에 일시적으로 불안정했음) 당연히 B가 나올줄 알았는데, A도 B도 아닌 README 기반의 만든적도 없는 배포 X가 나왔습니다... 왜였을까요...? Action 사용하기 이전 시절의 (Jekyll 등을 지원하던) GitHub Pages 빌드 방식이 남아있어서 뭔가 꼬였는지...

암튼 블로그 많이 놀러와주세요,,, 게임 추천으로 시작합니다 (포스트도 아니고 인덱스 페이지에서)

9
2
2
1
1
7

https://github.com/rust-lang/rust/pull/145602 오늘의 기여

r#"test"#suffix 같이 raw 문자열 리터럴에 유효하지 않은 접미사가 있을 때, 적절한 오류 메시지를 출력하지 못하는 문제를 수정했다. 이것저것 테스트 해본 결과 접미사 바로 뒤에 다른 토큰이 따라오는 경우에만 이 현상이 발생했다.

처음에는 렉서 단에서 유효하지 않은 접미사가 있는지 감지하도록 했지만, LitKind::from_token_lit에서도 접미사를 검사하고 있어서 중복으로 오류 메시지가 생성되는 문제가 발생했고, 추가로 attribute를 파싱할 때 시원하게 다 터지는 문제가 발생해서 이건 좋은 접근 방법이 아니였다.

그래서 대안으로 parse_expr_lit 함수를 수정하고 LitKind::from_token_lit을 사용해 파서 쪽에서 리터럴을 검증하고 적절하게 오류를 생성하도록 했다. https://github.com/rust-lang/rust/blob/8365fcb2b840c95eeb0bc377af8bd498fad22245/compiler/rustc_parse/src/parser/expr.rs#L1561-L1570

4

洪 民憙 (Hong Minhee) shared the below article:

초보자를 위한 하스켈 프로그램 상세 안내

박준규 @curry@hackers.pub

이 글은 하스켈 초보자를 위해 등호(=) 기호를 기준으로 텍스트를 정렬하는 간단한 명령줄 프로그램을 단계별로 개발하는 과정을 상세히 설명합니다. 저자는 `Data.Text` 라이브러리를 사용하여 문자열을 효율적으로 처리하고, `breakOn`, `length`, `replicate` 등의 함수를 활용하여 각 줄의 등호 위치를 맞추는 방법을 소개합니다. 특히 `maximumMay` 함수를 통해 발생할 수 있는 예외 상황을 `Maybe` 타입과 패턴 매칭으로 안전하게 처리하는 방법을 강조합니다. 마지막으로, `interact` 함수를 사용하여 순수 함수를 명령줄 도구로 변환하는 방법을 보여주며, 독자는 이 글을 통해 하스켈의 기본적인 문법과 함수형 프로그래밍의 핵심 개념을 실용적인 예제를 통해 배울 수 있습니다.

Read more →
8

박사과정을 하면 한번쯤은 내가 교수가 된다면 뭘 해볼까 생각해보게 되는 것 같다. 나의 경우에는 FPGA를 하나 사서 하드웨어부터 Verilog로 짜올려서 운영체제, 컴파일러를 만들고 C로 ray tracing을 짜는 두 학기짜리 프로젝트 과목을 해보고 싶다…만 이러면 조교가 죽어나갈 것을 알기에 꿈만 꿔본다.

14
2
1
6
2
6
5

단체 메일에서 BCC로 리스트를 넣어 보내야 할걸 TO에 넣어서 보낸걸 받고서 이제 이건 사람이 실수하기 너무 쉬운 구조가 아닌걸까 싶은 생각이 들었다. 차라리 이메일 서버 혹은 서비스에서 TO나 CC 목록에 수신인이 10명 이상이 있는데도 BCC가 아예 비어있다면 메일을 보내기 전에 경고를 띄워서 실수를 시스템적으로 막아야 하지 않을까하는 생각이 들었다.

BCC로 리스트를 넣어 보내야 하는데 모든 수신인을 TO에 넣은 단체 메일
5
7

I wrote an op-ed on the world-class STEM research ecosystem in the United States, and how this ecosystem is now under attack on multiple fronts by the current administration: newsletter.ofthebrave.org/p/im

0

바이브 코딩?으로 홈페이지 리뉴얼 하면서 느낀 점:

예전에도 그랬지만, 이제는 더욱더 메이저 오픈소스 툴을 써야 한다. hugo로 만든 웹페이지 W3C Validator 에러, 워닝 메시지 긁어서 hugo로 만들었는데 이게 왜 뜨지? 했더니, 어 이거는 자주 하는 실수인데 해결책은 이거다, 라고 바로 알려주네.

소스 코드와 결과물들이 많아 학습이 잘 된 툴과 아닌 툴의 생산성 차이가 무섭게 난다... 오픈소스 아니면 그냥 유튜브, 문서들 요약정리한 수준인 경우가 많은데 소스 코드 들여다 본 LLM은 완전히 다른 수준의 응답을 해 줌.

3

conal 리팩토링하면서 느끼는건데, 그래프 다루는 코드는 검증하는게 특히 어렵다. 특히 중요한 성질들을 타입으로 보장을 못해서 테스트와 assert 문으로 때우는수밖에 없다. 아마 하스켈로 했더라도 별반 다르지 않았을듯.

5
3

わざわざこんなことするのには理由があって、結局フレームワークと統合するにも今のアプローチだと限界があるっていうのが1つの理由 (今の方法だとその新しいフレームワークの方法 (FastAPIみたいにStarletteベースにする)よりも統合が弱くなる)。もう一つはapkitだから別のプロトコルに対応させるのは明らかに変だっていうこと。まぁ後者はATとかサポートするか怪しいから適当

2

apmodelとapsigの上に構築されたapkitの上に構築されたStarletteをベースとしたActivityPubフレームワークっていうとんでもなくわかりにくい書き方のものが生まれそう

3