Profile img

박준규

@curry@hackers.pub · 319 following · 172 followers

darcs hub
hub.darcs.net/vincent
Hackage
hackage.haskell.org/user/JoonkyuPark

System.IO.readFile 쓰지 마세요.

System.IO.readFile 쓰지 마세요.

System.IO.readFile 쓰지 마세요.

첫째, System.IO.readFileString 을 반환합니다. 이건 심각한 문제입니다. String 을 쓰지 마세요. 외부 세계와 I/O 를 할 때에는 ByteString 을 써야 합니다. 유니코드 문자열을 다룰 때에는 Text 를 쓸 수 있습니다. String 은 시간적으로도 공간적으로 비효율적입니다. 이건 어쩔 수 없습니다. 하스켈은 리눅스 커널보다 오래됐습니다. 그리고 하스켈이 String 을 만들 때에는 아직 하스켈에 모나드도 없던 시절이며, 타입 클래스가 과연 유용하겠는가를 두고 의견이 분분하던 시절이며, 파일 하나가 100 메가바이트가 넘어간다는 것이 과대망상으로 여겨지던 시절입니다. 특히 유니코드보다 더 먼저 나온 언어에 적절한 유니코드 문자열 타입이 있을 수는 없었습니다. 아무튼 String 은 레거시입니다. System.IO.readFile 로 그림 파일을 읽는 프로그래머는 사후세계에서 JPEG XL 파일을 십육진법 표기로 1 바이트씩 읽은 뒤 종이에 그려 내는 형벌에 처해집니다. String 을 쓰지 마세요.

둘째, System.IO.readFileFilePath 를 요구합니다. FilePath 도 사실 String 입니다. 그냥 별명(type synonym)이에요. 이것은 String 이기 때문에 비효율적이며, String 은 문자열이지 바이트열이 아니기 때문에 (인코딩을 전혀 통제할 수 없기 때문에) 파일 경로를 표현하는 타입으로 부적절합니다.

해결책: 먼저 System.OsPath 의 설명을 읽어 보세요. 그리고, file-io 패키지의 System.File.OsPath 모듈을 읽어 보세요. 여기 있는 함수들의 설명을 openBinaryFile 부터 하나씩 읽어보고 쓰세요. 이것들은 파일 경로에 OsPath 를 쓰기 때문에 String 의 비효율이 없고 인코딩도 올바르게 처리할 수 있습니다. 입출력 데이터에는 ByteString 을 씁니다. 바이트열을 유니코드 문자열로 변환할 때에는 예를 들어 Data.Text.Encoding.decodeUtf8Lenient 를 쓸 수 있습니다. 그럼 이제

  • 간단히 System.File.OsPath.readFile' 에게 OsPath 를 넘기고 ByteString 을 효율적으로 받아 와서 국밥처럼 든든하게 메모리에 올려 두고 작업을 하든지
  • 전국구 마법사라면 복대는 기본이라고 외치며 withBinaryFile앙갓썸Iteratee I/O 로 절묘하게 엮어서 뭔가 개멋있게 하든지
  • 하스켈 갓고수이기 때문에 흑마법사답게 보일러실 문을 따고 지하로 들어가 포… 포… 으악! P 로 시작하는 그것을 획득하여 누구도 예상할 수 없는 타이밍에 hGetBuf 의 암기를 슉. 슈슉. 슈슈슉. 슉. 날리든지

아무튼 이제는 String 을 놓아주어야 합니다.

7

Vim에서 Quickfix List라는 걸 처음 알게 되었다.

기존 코딩 흐름은

G 코딩 코딩 Vim을 닫는다. Vim을 닫는다. 코딩->Vim을 닫는다. cabal build cabal build Vim을 닫는다.->cabal build 에러 확인 에러 확인 cabal build->에러 확인 Vim을 연다. Vim을 연다. 에러 확인->Vim을 연다. 에러가 발생한 행(row)으로 간다. 에러가 발생한 행(row)으로 간다. Vim을 연다.->에러가 발생한 행(row)으로 간다. 에러가 발생한 행(row)으로 간다.->코딩

이랬는데 Quickfix List를 이용하면

G 코딩 코딩 :make :make 코딩->:make :copen :copen :make->:copen Enter를 눌러서 에러가 발생한 행으로 이동 Enter를 눌러서 에러가 발생한 행으로 이동 :copen->Enter를 눌러서 에러가 발생한 행으로 이동 Enter를 눌러서 에러가 발생한 행으로 이동->코딩

이렇게 Vim을 나가지 않고도 빌드 결과를 확인하고 에러가 발생하면 그곳으로 바로 점프할 수 있다!

.vimrc에 이렇게만 적으면 된다.

set makeprg=cabal\ build
2

Vim에서 Quickfix List라는 걸 처음 알게 되었다.

기존 코딩 흐름은

G 코딩 코딩 Vim을 닫는다. Vim을 닫는다. 코딩->Vim을 닫는다. cabal build cabal build Vim을 닫는다.->cabal build 에러 확인 에러 확인 cabal build->에러 확인 Vim을 연다. Vim을 연다. 에러 확인->Vim을 연다. 에러가 발생한 행(row)으로 간다. 에러가 발생한 행(row)으로 간다. Vim을 연다.->에러가 발생한 행(row)으로 간다. 에러가 발생한 행(row)으로 간다.->코딩

이랬는데 Quickfix List를 이용하면

G 코딩 코딩 :make :make 코딩->:make :copen :copen :make->:copen Enter를 눌러서 에러가 발생한 행으로 이동 Enter를 눌러서 에러가 발생한 행으로 이동 :copen->Enter를 눌러서 에러가 발생한 행으로 이동 Enter를 눌러서 에러가 발생한 행으로 이동->코딩

이렇게 Vim을 나가지 않고도 빌드 결과를 확인하고 에러가 발생하면 그곳으로 바로 점프할 수 있다!

.vimrc에 이렇게만 적으면 된다.

set makeprg=cabal\ build

이때 auto write를 이용하면 코드 수정 후 따로 :w로 저장하지 않아도 되고

autocmd QuickFixCmdPost make cwindow

를 쓰면 에러가 있을 때 Quickfix List가 자동으로 나타남.

2

Vim에서 Quickfix List라는 걸 처음 알게 되었다.

기존 코딩 흐름은

G 코딩 코딩 Vim을 닫는다. Vim을 닫는다. 코딩->Vim을 닫는다. cabal build cabal build Vim을 닫는다.->cabal build 에러 확인 에러 확인 cabal build->에러 확인 Vim을 연다. Vim을 연다. 에러 확인->Vim을 연다. 에러가 발생한 행(row)으로 간다. 에러가 발생한 행(row)으로 간다. Vim을 연다.->에러가 발생한 행(row)으로 간다. 에러가 발생한 행(row)으로 간다.->코딩

이랬는데 Quickfix List를 이용하면

G 코딩 코딩 :make :make 코딩->:make :copen :copen :make->:copen Enter를 눌러서 에러가 발생한 행으로 이동 Enter를 눌러서 에러가 발생한 행으로 이동 :copen->Enter를 눌러서 에러가 발생한 행으로 이동 Enter를 눌러서 에러가 발생한 행으로 이동->코딩

이렇게 Vim을 나가지 않고도 빌드 결과를 확인하고 에러가 발생하면 그곳으로 바로 점프할 수 있다!

.vimrc에 이렇게만 적으면 된다.

set makeprg=cabal\ build
6
9
1

탐라에 개발자분들이 많은거 같아서 여쭤봐요...

DBA나 데이터 엔지니어, 데이터 애널리스트, 쿼리 전문가에 대해서 어떻게 생각하시나요...!!!

꼭 필요한 존재는 아니라고 생각하시나요...!

3

하스켈에서 다음과 같은 에러를 만날 경우에

withFile: resource busy (file is locked)

readFile 대신 readFile'을 써보셔요!

  • readFile은 lazy 버전이고
  • readFile'은 strict 버전입니다!

System.IO 모듈 문서에 다음과 같은 설명이 있습니다.

경고: readFile 연산은 파일의 전체 내용을 모두 소비할 때까지 그 파일에 대해 부분적으로 닫힌(semi-closed) 핸들을 유지한다. 따라서 이전에 readFile로 연 파일에 대해(writeFile 등을 사용하여) 쓰기를 시도하면, 일반적으로 isAlreadyInUseError 오류와 함께 실패하게 된다.

4

12() 6() 서울에서 開催(개최)되는 liftIO 2025에서 〈Optique: TypeScript에서 CLI 파서 컴비네이터를 만들어 보았다〉(假題(가제))라는 主題(주제)發表(발표)를 하게 되었습니다. 아직 liftIO 2025 티켓은 팔고 있으니, 函數型(함수형) 프로그래밍에 關心(관심) 있으신 분들의 많은 參與(참여) 바랍니다!

11
5
4

참 쉽죠?

박준규 @curry@hackers.pub

하스켈(Haskell) 프로젝트를 처음 시작하는 사람들을 위해, `cabal`을 이용한 간단한 실행 파일 생성 과정을 소개합니다. 이 글은 `ghc`와 `cabal`이 `ghcup`을 통해 이미 설치되었다는 전제하에, 프로젝트 디렉터리 생성부터 기본적인 파일 구조 초기화, 그리고 빌드 및 실행까지의 단계를 최소한의 노력으로 빠르게 따라 할 수 있도록 안내합니다. `cabal init` 명령어를 사용하여 프로젝트를 초기화하고, 생성된 `app/Main.hs` 파일을 통해 "Hello, Haskell!"을 출력하는 예제를 통해 하스켈 개발의 첫걸음을 쉽게 내딛을 수 있도록 돕습니다. 이 글은 복잡한 설정 없이 하스켈 프로젝트를 시작하고 실행하는 기본적인 방법을 제시하며, 독자들이 하스켈의 세계에 더 쉽게 접근할 수 있도록 돕는 것을 목표로 합니다.

Read more →
10
2
3
0
1
2

박준규 shared the below article:

"expression"은 "표현식"이 아니라 그냥 "식"

蛇崩 (じゃくずれ) @ja@hackers.pub

이 글은 프로그래밍 용어 "expression"을 "표현식"이 아닌 간결한 "식"으로 번역해야 한다고 주장합니다. 필자는 "expression"이 수학에서 유래되었으며, 수학에서는 이미 "식"으로 번역되어 사용되고 있음을 지적합니다. 또한, 프로그래머들이 "표현식"을 선호하는 이유로 사전적 정의와 초·중등 교육에서 비롯된 선입견을 들지만, 실제로는 "식"으로 번역해도 의미 전달에 전혀 문제가 없다고 강조합니다. 오히려 "표현식"은 "representation"의 번역어인 "표현"과 혼동될 수 있으며, "정규표현식"과 같이 불필요하게 긴 용어를 만들어낼 수 있다고 비판합니다. 결론적으로, 필자는 "expression"을 "식"으로 번역하는 것이 더 정확하고 간결하며, 전산학 용어의 일관성을 유지하는 데 도움이 된다고 주장하며, "정규식"이라는 간결한 용어 사용을 옹호합니다.

Read more →
10
0
0

《하스켈로 배우는 프로그래밍》(2009, 대림) 옮긴이의 말

박준규 @curry@hackers.pub

이 글은 2009년 출간된 《하스켈로 배우는 프로그래밍》의 옮긴이 머리말을 공유한 것으로, 하스켈이 단순한 학술적 언어를 넘어 실무적인 범용 언어로 발전한 배경과 그 우수성을 설명합니다. 다양한 업계에서 상용 소프트웨어의 핵심 기술로 활용되는 하스켈은 효율적인 컴파일 언어이면서도 스크립트 언어처럼 빠른 개발이 가능하며, 안전한 정적 타입 언어이면서도 동적 타입 언어처럼 유연한 특징을 지닙니다. 특히 타입 클래스라는 독특한 기능을 통해 코드의 확장성을 높이고, 오브젝트 중심 언어의 인터페이스보다 더 유연하게 대처할 수 있음을 강조합니다. 하스켈은 프로그래밍 언어 연구 성과를 충실히 반영하여 개발 효율성과 코드 안정성을 동시에 추구하는 IT 전문가들에게 매력적인 선택이 될 수 있으며, 이 글은 하스켈의 장점을 다양한 예시와 함께 소개하여 독자들이 하스켈에 대한 이해를 높이고 더 깊이 있는 학습으로 나아가도록 안내합니다.

Read more →
7

박준규 shared the below article:

안녕 세계!

김태희 (탐정토끼) @stelo_kim@hackers.pub

일론 머스크에 대항하여 자유/오픈소스 생태계를 지키기 위해 Fediverse 활동을 시작하려는 여정을 소개합니다. 기존 해커스펍 계정을 활용하여 글을 작성하고, 트위터에는 미리보기 링크를 공유하는 방식으로 소통할 계획입니다. Fediverse에서의 활동을 통해 자유와 오픈소스 가치를 옹호하고, 더 많은 사람들과 교류하며 기여할 수 있기를 기대합니다.

Read more →
12

하스켈에서 레코드 타입을 json으로 인코딩할 때 타입이 Maybe인 필드의 값이 Nothing이면 그 타입의 값은 null로 변환된다.(deriving Generic 했다면)

이때 null이 아니라 해당 필드 자체를 포함하지 않게 하려면 다음과 같이 하면 된다.

{-# LANGUAGE TemplateHaskell #-}

import Data.Aeson.TH

data Foo = ...

deriveJSON defaultOptions { omitNothingFields = True } ''Foo

위와 같이 deriveJSON 했다면 기존에 선언했던 아래 구문은 지워야 한다.

instance FromJSON Foo
instnace ToJSON Foo
0

하스켈에서 레코드 타입을 json으로 인코딩할 때 타입이 Maybe인 필드의 값이 Nothing이면 그 타입의 값은 null로 변환된다.(deriving Generic 했다면)

이때 null이 아니라 해당 필드 자체를 포함하지 않게 하려면 다음과 같이 하면 된다.

{-# LANGUAGE TemplateHaskell #-}

import Data.Aeson.TH

data Foo = ...

deriveJSON defaultOptions { omitNothingFields = True } ''Foo

위와 같이 deriveJSON 했다면 기존에 선언했던 아래 구문은 지워야 한다.

instance FromJSON Foo
instnace ToJSON Foo
3
1

하스켈에서 Either a bToJSON 인스턴스 구현이 약간 애매하다.

json 객체의 키 값으로 "Left""Right"를 넣는 것 같다. 그런 방식으로 사용하는 사람은 거의 없을 것 같은데... 아무튼 그래서 newtype은 쓰지 않고 인스턴스를 오버라이딩 하고 싶은데 대충 찾아보면 인터넷이나 LLM의 첫번째 대답은 OverlappingInstances 확장을 쓰라고 안내하는데 이건 deprecated 됐다. 대신 다음과 같은 프라그마(pragma)를 쓰면 된다.

  • OVERLAPPING
  • OVERLAPPABLE
  • OVERLAPS

프라그마는 확장과 다른데 확장은 확장을 적은 파일 전체에 적용되지만 프라그마는 해당 인스턴스에만 적용된다.

다음과 같이 사용한다.

instance {-# OVERLAPPING #-} ToJSON a => ToJSON (Either Foo a) where
  toJSON = ...

이렇게 하면 고아[1]를 만들었다며 컴파일러가 내 인성을 비난하겠지만 Either a b를 통째로 오버라이딩 한 것도 아니고 별로 문제가 될 것 같진 않다.


  1. 하스켈에서 타입이나 클래스가 정의된 모듈이 아닌 곳에 인스턴스를 선언할 때 그 인스턴스를 Orphan(고아) 인스턴스라고 한다. ↩︎

6
5
0
21
4
0
3
4
0
0

기후위기로 지표가 살기 불가능해져서 모두 실내/벙커 내에서 생활하는 상황 등

모두 태양을 보지 않고 인공적인 빛으로 살게 되는 세상이 되면

지구의 모든 조명을 동기화하면 타임존을 하나로 통일해도 되지 않을까?

1
0
0
1
3

@arkjunJuntai Park 이번에는 국토교통부로 이송되었습니다.

본 민원은 국도77호선 관련 내용으로, 민원처리법 제16조(민원문서의 이송)에 따라 순천국토관리사무소로 이송합니다.

G 한국도로교통공단 한국도로교통공단 여수시 여수시 한국도로교통공단->여수시 국토교통부 국토교통부 여수시->국토교통부

@arkjunJuntai Park

귀하께서 요청하신 둔병대교 VMS 운용 프로그램 사용자 접속 제한에 대해서는 최초 VMS 설치 시 운용하여 비밀번호가 노출됐던 프로그램은 삭제하고 내부 운용 프로그램 사용을 통해 관리자만 접근 할 수 있도록 조치하였음을 알려드립니다.

와, 진짜 이제 접속 안 됩니다! 국토교통부 공무원 여러분 고생하셨습니다.

8

@arkjunJuntai Park 이번에는 국토교통부로 이송되었습니다.

본 민원은 국도77호선 관련 내용으로, 민원처리법 제16조(민원문서의 이송)에 따라 순천국토관리사무소로 이송합니다.

G 한국도로교통공단 한국도로교통공단 여수시 여수시 한국도로교통공단->여수시 국토교통부 국토교통부 여수시->국토교통부

@arkjunJuntai Park

귀하께서 요청하신 둔병대교 VMS 운용 프로그램 사용자 접속 제한에 대해서는 최초 VMS 설치 시 운용하여 비밀번호가 노출됐던 프로그램은 삭제하고 내부 운용 프로그램 사용을 통해 관리자만 접근 할 수 있도록 조치하였음을 알려드립니다.

와, 진짜 이제 접속 안 됩니다! 국토교통부 공무원 여러분 고생하셨습니다.

8

lens 라이브러리의 타입들은 optics(광학기구)라고 불립니다. 여기에는 Prism, Lens, Iso, Traversal, Fold, Getter, Setter 같은 것들이 포함됩니다. 이 이름들 중 일부는 빛의 굴절에 대한 말장난에서 비롯되었습니다. 예를 들어, 렌즈(lens)는 망원경이 풍경의 작은 일부를 시야 가득히 채워 보이게 해주는 것이고, 프리즘(prism)은 흰빛을 분리하여 그 구성 색들을 드러내 줍니다. 어느 정도는 은유가 담겨 있지만, 이런 이름들은 깨달음을 주기보다는 귀여운 쪽에 가깝습니다. 따라서 이름 자체에 너무 깊이 집중하는 것은 권하지 않습니다.

— 《Finding Success (and Failure) in Haskell》, 158쪽

6

방금 따님이 폰으로 유튜브 쇼츠 넘기며 보는데
그 앞에서 마눌님이 개똥벌레 노래를 부르니
잠시후 개똥벌레 노래 부르는 쇼츠가 나옴 ㅋ

구글이 듣고 있다..

0
0

@arkjunJuntai Park 이번에는 국토교통부로 이송되었습니다.

본 민원은 국도77호선 관련 내용으로, 민원처리법 제16조(민원문서의 이송)에 따라 순천국토관리사무소로 이송합니다.

G 한국도로교통공단 한국도로교통공단 여수시 여수시 한국도로교통공단->여수시 국토교통부 국토교통부 여수시->국토교통부
1

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

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

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

4
4
1
1

보안관제 서비스 알아보니 정말 최소 옵션으로 하면 월 8만원까지 해줄 수 있다는데...

이게 고민스러운게 비싼 것 같아도, 요새 개인서버 운영자도 해킹당하면 변호사 선임 고려해야하는데 이게 기본 300만원 깨진단말이지

그런거 생각하면 저렴한거 아닌가 생각이 들기도...

1
0