타입스크립트에 있었으면 좋겠음

bgl gwyng
@bgl@hackers.pub · 84 following · 100 followers
슈티를 함께 만들 팀을 만들고 있습니다. 관심 있으신 분, 또는 잘 모르겠지만 이야기를 나눠보고 싶은 분도 bgl@gwyng.com으로 편하게 연락주세요.
GitHub
- @bglgwyng
shootee
- www.shootee.io
@tirr티르 저도 서브타이핑 기반인 TS에 상대적으로 쉽게 도입할 기능이 https://github.com/microsoft/TypeScript/issues/13219 이렇게 오랫동안 진행안되는게 불만입니다. 막상 TS 이펙트 라이브러리들은
|
로 흉내내서 잘 쓰고 있더라고요. Haskell처럼 대수적 이펙트는 구현할수있지만 서브타이핑 기반은 아닌 언어에선, 서브타이핑 흉내낸다고 타입레벨 차력쇼하고 있는데 맞는 방향인지 모르겠습니다.
@hongminhee洪 民憙 (Hong Minhee) I can't agree more. 'Java sucks' doesn't apply here at least. Subtyping plays really well in unioning error types.
@bglbgl gwyng Absolutely! You make a great point about subtyping—it's one of Java's underappreciated strengths for error handling. The exception hierarchy lets you catch specific exceptions or their broader subtypes as needed, giving you flexible error composition without extra syntax.
bgl gwyng shared the below article:
Revisiting Java's Checked Exceptions: An Underappreciated Type Safety Feature

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub
Despite their bad reputation in the Java community, checked exceptions provide superior type safety comparable to Rust's Result<T, E>
or Haskell's Either a b
—we've been dismissing one of Java's best features all along.
Introduction
Few features in Java have been as consistently criticized as checked exceptions. Modern Java libraries and frameworks often go to great lengths to avoid them. Newer JVM languages like Kotlin have abandoned them entirely. Many experienced Java developers consider them a design mistake.
But what if this conventional wisdom is wrong? What if checked exceptions represent one of Java's most forward-thinking features?
In this post, I'll argue that Java's checked exceptions were ahead of their time, offering many of the same type safety benefits that are now celebrated in languages like Rust and Haskell. Rather than abandoning this feature, we should consider how to improve it to work better with modern Java's features.
Understanding Java's Exception Handling Model
To set the stage, let's review how Java's exception system works:
-
Unchecked exceptions (subclasses of
RuntimeException
orError
): These don't need to be declared or caught. They typically represent programming errors (NullPointerException
,IndexOutOfBoundsException
) or unrecoverable conditions (OutOfMemoryError
). -
Checked exceptions (subclasses of
Exception
but notRuntimeException
): These must either be caught withtry
/catch
blocks or declared in the method signature withthrows
. They represent recoverable conditions that are outside the normal flow of execution (IOException
,SQLException
).
Here's how this works in practice:
// Checked exception - compiler forces you to handle or declare it
public void readFile(String path) throws IOException {
Files.readAllLines(Path.of(path));
}
// Unchecked exception - no compiler enforcement
public void processArray(int[] array) {
int value = array[array.length + 1]; // May throw ArrayIndexOutOfBoundsException
}
The Type Safety Argument for Checked Exceptions
At their core, checked exceptions are a way of encoding potential failure modes into the type system via method signatures. This makes certain failure cases part of the API contract, forcing client code to explicitly handle these cases.
Consider this method signature:
public byte[] readFileContents(String filePath) throws IOException
The throws IOException
clause tells us something critical: this method might fail in ways related to IO operations. The compiler ensures you can't simply ignore this fact. You must either:
- Handle the exception with a try-catch block
- Propagate it by declaring it in your own method signature
This type-level representation of potential failures aligns perfectly with principles of modern type-safe programming.
Automatic Propagation: A Hidden Advantage
One often overlooked advantage of Java's checked exceptions is their automatic propagation. Once you declare a method as throws IOException
, any exception that occurs is automatically propagated to the caller without additional syntax.
Compare this with Rust, where you must use the ?
operator every time you call a function that returns a Result
:
// Rust requires explicit propagation with ? for each call
fn read_and_process(path: &str) -> Result<(), std::io::Error> {
let content = std::fs::read_to_string(path)?;
process_content(&content)?;
Ok(())
}
// Java automatically propagates exceptions once declared
void readAndProcess(String path) throws IOException {
String content = Files.readString(Path.of(path));
processContent(content); // If this throws IOException, it's automatically propagated
}
In complex methods with many potential failure points, Java's approach leads to cleaner code by eliminating the need for repetitive error propagation markers.
Modern Parallels: Result Types in Rust and Haskell
The approach of encoding failure possibilities in the type system has been adopted by many modern languages, most notably Rust with its Result<T, E>
type and Haskell with its Either a b
type.
In Rust:
fn read_file_contents(file_path: &str) -> Result<Vec<u8>, std::io::Error> {
std::fs::read(file_path)
}
When calling this function, you can't just ignore the potential for errors—you need to handle both the success case and the error case, often using the ?
operator or pattern matching.
In Haskell:
readFileContents :: FilePath -> IO (Either IOException ByteString)
readFileContents path = try $ BS.readFile path
Again, the caller must explicitly deal with both possible outcomes.
This is fundamentally the same insight that motivated Java's checked exceptions: make failure handling explicit in the type system.
Valid Criticisms of Checked Exceptions
If checked exceptions are conceptually similar to these widely-praised error handling mechanisms, why have they fallen out of favor? There are several legitimate criticisms:
1. Excessive Boilerplate in the Call Chain
The most common complaint is the boilerplate required when propagating exceptions up the call stack:
void methodA() throws IOException {
methodB();
}
void methodB() throws IOException {
methodC();
}
void methodC() throws IOException {
// Actual code that might throw IOException
}
Every method in the chain must declare the same exception, creating repetitive code. While automatic propagation works well within a method, the explicit declaration in method signatures creates overhead.
2. Poor Integration with Functional Programming
Java 8 introduced lambdas and streams, but checked exceptions don't play well with them:
// Won't compile because map doesn't expect functions that throw checked exceptions
List<String> fileContents = filePaths.stream()
.map(path -> Files.readString(Path.of(path))) // Throws IOException
.collect(Collectors.toList());
This forces developers to use awkward workarounds:
List<String> fileContents = filePaths.stream()
.map(path -> {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
throw new UncheckedIOException(e); // Wrap in an unchecked exception
}
})
.collect(Collectors.toList());
3. Interface Evolution Problems
Adding a checked exception to an existing method breaks all implementing classes and calling code. This makes evolving interfaces over time difficult, especially for widely-used libraries and frameworks.
4. Catch-and-Ignore Anti-Pattern
The strictness of checked exceptions can lead to the worst possible outcome—developers simply catching and ignoring exceptions to make the compiler happy:
try {
// Code that might throw
} catch (Exception e) {
// Do nothing or just log
}
This is worse than having no exception checking at all because it provides a false sense of security.
Improving Checked Exceptions Without Abandoning Them
Rather than abandoning checked exceptions entirely, Java could enhance the existing system to address these legitimate concerns. Here are some potential improvements that preserve the type safety benefits while addressing the practical problems:
1. Allow lambdas to declare checked exceptions
One of the biggest pain points with checked exceptions today is their incompatibility with functional interfaces. Consider how much cleaner this would be:
// Current approach - forced to handle or wrap exceptions inline
List<String> contents = filePaths.stream()
.map(path -> {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
// Potential future approach - lambdas can declare exceptions
List<String> contents = filePaths.stream()
.map((String path) throws IOException -> Files.readString(Path.of(path)))
.collect(Collectors.toList());
This would require updating functional interfaces to support exception declarations:
@FunctionalInterface
public interface Function<T, R, E extends Exception> {
R apply(T t) throws E;
}
2. Generic exception types in throws clauses
Another powerful enhancement would be allowing generic type parameters in throws
clauses:
public <E extends Exception> void processWithException(Supplier<Void, E> supplier) throws E {
supplier.get();
}
This would enable much more flexible composition of methods that work with different exception types, bringing some of the flexibility of Rust's Result<T, E>
to Java's existing exception system.
3. Better support for exception handling in functional contexts
Unlike Rust which requires the ?
operator for error propagation, Java already automatically propagates checked exceptions when declared in the method signature. What Java needs instead is better support for checked exceptions in functional contexts:
// Current approach for handling exceptions in streams
List<String> contents = filePaths.stream()
.map(path -> {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
throw new RuntimeException(e); // Lose type information
}
})
.collect(Collectors.toList());
// Hypothetical improved API
List<String> contents = filePaths.stream()
.mapThrowing(path -> Files.readString(Path.of(path))) // Preserves checked exception
.onException(IOException.class, e -> logError(e))
.collect(Collectors.toList());
4. Integration with Optional<T>
and Stream<T>
APIs
The standard library could be enhanced to better support operations that might throw checked exceptions:
// Hypothetical API
Optional<String> content = Optional.ofThrowable(() -> Files.readString(Path.of("file.txt")));
content.ifPresentOrElse(
this::processContent,
exception -> log.error("Failed to read file", exception)
);
Comparison with Other Languages' Approaches
It's worth examining how other languages have addressed the error handling problem:
Rust's Result<T, E>
and ?
operator
Rust's approach using Result<T, E>
and the ?
operator shows how propagation can be made concise while keeping the type safety benefits. The ?
operator automatically unwraps a successful result or returns the error to the caller, making propagation more elegant.
However, Rust's approach requires explicit propagation at each step, which can be more verbose than Java's automatic propagation in certain scenarios.
Kotlin's Approach
Kotlin made all exceptions unchecked but provides functional constructs like runCatching
that bring back some type safety in a more modern way:
val result = runCatching {
Files.readString(Path.of("file.txt"))
}
result.fold(
onSuccess = { content -> processContent(content) },
onFailure = { exception -> log.error("Failed to read file", exception) }
)
This approach works well with Kotlin's functional programming paradigm but lacks compile-time enforcement.
Scala's Try[T]
, Either[A, B]
, and Effect Systems
Scala offers Try[T]
, Either[A, B]
, and various effect systems that encode errors in the type system while integrating well with functional programming:
import scala.util.Try
val fileContent: Try[String] = Try {
Source.fromFile("file.txt").mkString
}
fileContent match {
case Success(content) => processContent(content)
case Failure(exception) => log.error("Failed to read file", exception)
}
This approach preserves type safety while fitting well with Scala's functional paradigm.
Conclusion
Java's checked exceptions were a pioneering attempt to bring type safety to error handling. While the implementation has shortcomings, the core concept aligns with modern type-safe approaches to error handling in languages like Rust and Haskell.
Copying Rust's Result<T, E>
might seem like the obvious solution, but it would represent a radical departure from Java's established paradigms. Instead, targeted enhancements to the existing checked exceptions system—like allowing lambdas to declare exceptions and supporting generic exception types—could preserve Java's unique approach while addressing its practical limitations.
The beauty of such improvements is that they'd maintain backward compatibility while making checked exceptions work seamlessly with modern Java features like lambdas and streams. They would acknowledge that the core concept of checked exceptions was sound—the problem was in the implementation details and their interaction with newer language features.
So rather than abandoning checked exceptions entirely, perhaps we should recognize them as a forward-thinking feature that was implemented before its time. As Java continues to evolve, we have an opportunity to refine this system rather than replace it.
In the meantime, next time you're tempted to disparage checked exceptions, remember: they're not just an annoying Java quirk—they're an early attempt at the same type safety paradigm that newer languages now implement with much celebration.
What do you think? Could these improvements make checked exceptions viable for modern Java development? Or is it too late to salvage this controversial feature? I'm interested in hearing your thoughts in the comments.
uv2nix는 uv보다 구리고, cabal2nix는 cabal보다 구린데, Nix는 uv + cabal + ... 보다 낫다. Nix 커뮤니티를 키우려면, 후자를 이해시키고(쉬움) 전자에 대해 익스큐즈하도록 설득해야한다(어려움) .
Hot take: Despite their bad reputation in the Java community, checked exceptions provide superior type safety comparable to Rust's Result<T, E>
or Haskell's Either a b
—we've been dismissing one of Java's best features all along.
@hongminhee洪 民憙 (Hong Minhee) I can't agree more. 'Java sucks' doesn't apply here at least. Subtyping plays really well in unioning error types.
@bglbgl gwyng 갑자기 딴 이야기긴 한데,
@bglbgl gwyng 님은 Haskell 툴체인으로 Stack 쓰시나요, 아니면 Cabal 쓰시나요? 몇 년 전부터 Stack을 썼는데 요즘엔 Stack 쪽이 개발이 잘 안 되는 것 같아서 다시 Cabal로 넘어가야 하나 고민하고 있거든요…
@hongminhee洪 民憙 (Hong Minhee) 저는 Nix를 쓰고 있습니다. 한동안 Haskell 안쓰고있다가 오랜만에 돌아왔더니 다들 Nix 쓰고있어서 그냥 따라 쓰는 상태입니다. Nix가 해결하려는 문제와 방향은 공감하지만, Haksell + Nix가 막 엄청 좋은지는 잘 모르겠는 상태에요.
Nix로 그냥 GHC랑 Cabal, Stack 버전만 잡고 나머지는 Cabal, Stack 등의 기존 하스켈 툴링에 맡기는 방법이 있고, 또 Nix가 패키지 다운받아서 빌드하는 역할까지 대신해버리는 방법이 있는데, 제가 쓰고 있는 방법은 후자입니다.
모든 자바스크립트 개발자들이 단 하나의 패키지 매니저와 단 하나의 빌드 시스템, 단 하나의 모듈 시스템을 사용하면 좋겠다고 진심으로 생각한다
@parksbSimon Park 어디는 망치가 너무 많아서 문제고 어디는 너무 적어서 문제죠ㅋㅋ
모든 자바스크립트 개발자들이 단 하나의 패키지 매니저와 단 하나의 빌드 시스템, 단 하나의 모듈 시스템을 사용하면 좋겠다고 진심으로 생각한다
C++ 표준화 위원회(WG21)에게 C++의 원 저자인 비야네 스트롭스트룹Bjarne Stroustrup이 보낸 메일이 이번 달 초에 본인에 의해 공개된 모양이다. C++가 요즘 안전하지 않은 언어라고 열심히 얻어 맞고 있는 게 싫은지 프로파일(P3081)이라고 하는 언어 부분집합을 정의하려고 했는데, 프로파일이 다루는 문제들이 아주 쉬운 것부터 연구가 필요한 것까지 한데 뒤섞여 있어 구현이 매우 까다롭기에 해당 제안이 적절하지 않음을 올해 초에 가멸차게 까는 글(P3586)이 올라 오자 거기에 대한 응답으로 작성된 것으로 보인다. 더 레지스터의 표현을 빌면 "(본지가 아는 한) 스트롭스트룹이 이 정도로 강조해서 말하는 건 2018년 이래 처음"이라나.
여론은 당연히 호의적이지 않은데, 기술적인 반론이 대부분인 P3586과는 달리 해당 메일은 원래 공개 목적이 아니었음을 감안해도 기술적인 얘기는 쏙 빼 놓고 프로파일이 "코드를 안 고치고도 안전성을 가져 갈 수 있다"는 허황된 주장에 기반해 그러니까 프로파일을 당장 집어 넣어야 한다고 주장하고 있으니 그럴 만도 하다. 스트롭스트룹이 그렇게 이름을 언급하지 않으려고 했던 러스트를 굳이 들지 않아도, 애당초 (이 또한 계속 부정하고 싶겠지만) C++의 주요 장점 중 하나였던 강력한 C 호환성이 곧 메모리 안전성의 가장 큰 적이기 때문에 프로파일이 아니라 프로파일 할아버지가 와도 안전성을 진짜로 확보하려면 코드 수정이 필수적이고, 프로파일이 그 문제를 해결한다고 주장하는 건 눈 가리고 아웅이라는 것을 이제는 충분히 많은 사람들이 깨닫지 않았는가. 스트롭스트룹이 허황된 주장을 계속 반복하는 한 C++는 안전해질 기회가 없을 듯 하다.
저는 AI에게 감사 인사를 하는 데에도 돈이 든다는 걸 깨달아버려서, 이제는 감사도 표하지 않는 삭막한 인간이 되고야 말았습니다.
@nyeongAn Nyeong (安寧) 이슈 설명할 힘도 없을때는 ai한테 '${이슈 내용} ㄱㄱ' 라고만 쳐도 열심히 잘해주는데 그럴땐 미안한 맘이 듭니다
시간이 좀 지나서 그런가, 이제 계엄자체는 그냥 또라이가 또라이짓했다 정도로 생각되는데, 그 이후 탄핵 과정에서 뭔 말같지도 않는 어거지를 부리는거 때문에 자꾸 스트레스받는다.
그동안 동료들한테 Cursor 쓰자고했는데 그들이 오소독스 Emacs 매니아들이란 문제가 있었다.
작년에 Nix로 nvidia gpu 지원까지 포함해서 구축해놓은 k3s 클러스터에다가, 오늘 아침에 1시간만에 aider로 쓸수있게 DeepSeek R1을 띄웠고 한번 써보자고 했다. 최근에 한 것 중 가장 가성비 좋은 작업인듯 하다.
타임라인과 RSS 피드에 단문 없이 게시글만 보는 필터를 추가했습니다.
@campanulaLuminα 저의 경우는 React Native라서 백엔드로 SQLite를 쓰고 있어서 괜찮습니다. 생각해보니 RxDB 등의 경우는 웹도 지원해야해서 join을 지원하는게 어려울거 같긴하네요.
JS로 짜여진, join이 되는 reactive한 로컬 DB가 필요한데요. RxDB, SignalDB는 join이 안 돼서 탈락입니다. join을 안하면 되지 않냐 할수 있는데 어떤 특이한 로직 때문에 꼭 필요합니다. 지금은 직접 sqlite 호출하는 누더기 코드로 돌아가고 있는데요.
그 코드를 리팩토링해서 제대로 된걸 만들까 말까 고민중인데, 사실 잘만들어진게 있으면 그걸 쓰고 싶습니다. 제 요구사항을 만족하는 라이브러리가 있을까요?
@dwndiaowinner 님 덕분애 Hackers' Pub에 중국어 번역이 추가되었습니다!
또한, 언어 설정이 추가되어, 자신이 선호하는 복수의 언어를 선택할 수 있게 되었습니다. 이 설정은 당장은 팔로 추천에만 쓰이고 있지만, 앞으로 자동 번역이나 알고리즘 타임라인 등에 요긴하게 쓰일 예정입니다.
영어권 웹을 보다보면 autism이 한국어에서의 '자폐'보다 부정적인 늬앙스가 훨씬 덜하단 느낌을 받는다. STEM 너드들이 본인이 autistic하다고 하는 경우를 종종 보는데, 자조적인 느낌이 좀 있지만 완전 딥다크한거 같진않고, 이분법적이기보단 스펙트럼으로 보는거 같다.
@arkjunJuntai Park 사실상 저만 쓰는 소프트웨어입니다. 😂
@hongminhee洪 民憙 (Hong Minhee)
@arkjunJuntai Park 이유는 모르겠는데 개멋있네요ㄷㄷ
asbubam 님의 내가 만난 멋진 SRE
SRE 에 대한 얘기지만 멋대로(?) 개발자에 대입해서 보았습니다. 와닿는 내용을 일부 인용해 보면
여기 우리 다 처음에 그랬고 오늘도 여전히 매일 고민하고, 부딪히고, 배우면서 앞으로 나아가고 있으니까
멋진 SRE는, 도무지 답이 보이지 않는 문제를 만나도, “원래 그런거니까 흐흐” 하고 문제에 달려들어요. 내 힘으로 부족한 일은, 옆에있는 동료와 함께 반드시 해결할 수 있다고 믿어요
회사 동료들에게도 말해주고 싶은 내용들이네요. 동료들이 있으니께 걱정하지 말고 나아가라구요.
이番에 @lqezPark Hyunwoo 님의 《우리의 코드를 찾아서》에 出演하여 #페디버스, #ActivityPub, #Fedify, #Hollo 等에 關해 이야기를 나눴습니다. Fedify와 Hollo의 開發 祕話 같은 게 궁금하시다면 한 番 보셔도 재밌을지도 모르겠습니다. ㅎㅎㅎ
https://snix.dev/ 저는 Rust를 못해서 기여를 못하지만 유망한 프로젝트라고 생각합니다. Rust 고수분들이 관심가져주시면 좋겠네요.
Hackers' Pub에 RSS 기능을 추가했습니다. 정확히는 RFC 4287, 일명 Atom 명세를 구현했습니다. RSS 디스커버리도 구현했기 때문에, Hackers' Pub 사용자의 프로필 페이지 링크를 RSS 앱에 추가하면 구독이 가능합니다. 확실한(?) 피드 링크를 알고 싶으시면 프로필 링크 뒤에 /feed.xml을 붙이시면 됩니다. 예를 들어, 제 피드 링크는 https://hackers.pub/@hongminhee/feed.xml입니다.
바둑에 '묘수 3번두면 바둑은 진다'라는 말이 있는데, 프로그래밍에 비슷한 말이 있을까요
어렸을 때는 Smalltalk나 Lisp 같은 언어에 마음을 많이 빼앗겼는데 (아마도 당시 쿨한 언어였던 Python이나 Ruby의 영향…) Haskell을 접한 뒤로는 언어 취향이 아주 많이 바뀐 것 같다. 일단 동적 타입 언어를… 싫어하는 정도까진 아니지만, 쓰면서 불안함을 느끼게 됐다.
Nix를 보며 알수있는건, 사람들이 메타프로그래밍을 하기 좋은 언어로 메타프로그래밍을 하는게 아니라, 런타임이 좋은 언어로 메타프로그래밍을 한다는 것이다.
Nix의 런타임이 좋다는건 일반적인 의미에서(성능이 빠르다거나) 좋다기보다는 '재현가능한 캐싱되는 빌드'라는 런타임이 아주 많은 동작을 커버하는데 Nix가 그걸 구현했다는 얘기다. 그러니까 사람들은 큰 프로그램을 쌓아올릴 대들보가 될만한 런타임이 있으면 거기서 부터 메타프로그래밍을 시작해버린다. Nix가 언어는 구리고(애초에 엄청 잘만들려고 한거같지도 않음) 메타프로그래밍을 잘하기위한 어떠한 장치도 없음에도 가장 아래에 위치할수있어서 그 역할이 맡겨져버린다.
그래서 유용한 런타임과 오브젝트 언어(또는 DSL)을 표현할 문법에 대한 좋은 아이디어가 있으면, 좀더 나은 메타프로그래밍을 하기위한 언어를 만들수 있을거라고 생각한다.
이제 게시글(긴 글)도 단문처럼 공유가 가능해졌습니다. 그리고, 타임라인에 게시글에 대한 댓글이 보이는 방식을 수정하였습니다.
사실 알고보니 이것도, 저것도 모나드였다... 하는 예시는 많은데 Category
의 예시는 뭐가 있을까? 그럼 설명이 훨씬 편해질텐데 말이다.
좀 인위적이지만 쉬운 예시를 하나 만들어보자면, 어떤 함수의 실행에 비용을 부여하는 것이다.
data Costful a b = Costful (a -> IO b) Int
f :: Costful Int String
g :: Costful String Bool
요런 정의를 생각해볼때
f . g
는 f
와 g
의 동작은 합성하고, 비용은 +
한 것이 될것이다.
instance Category where
Costful f c1 . Costful g c2 = Costful (f . g) (c1 + c2)
요렇게 말이다.
이때 f . g
의 비용은 함수를 실행하기 전에도 알수있다.
반면 그냥 f
, g
를 모나딕한 함수로 정의하고 f >=> g
이런식으로 합성했을땐, 함수를 실제로 실행하기 전에는 비용을 알수 없다. >=>
또는 >>=
의 정의를 생각해보면 쉽게 알수 있다.
Category
인스턴스는 정적인 정보를 추가로 가지고 있는 함수, 또는 함수보다 표현력이 약한데 비스무리한거(그래서 정적인 정보가 더많은) 것을 다룰때 유용하다.
Costful (f <=< g) (c1 + c2)
로 정정.
그나저나 하스켈 신택스 하이라이팅되는게 감동이군요
사실 알고보니 이것도, 저것도 모나드였다... 하는 예시는 많은데 Category
의 예시는 뭐가 있을까? 그럼 설명이 훨씬 편해질텐데 말이다.
좀 인위적이지만 쉬운 예시를 하나 만들어보자면, 어떤 함수의 실행에 비용을 부여하는 것이다.
data Costful a b = Costful (a -> IO b) Int
f :: Costful Int String
g :: Costful String Bool
요런 정의를 생각해볼때
f . g
는 f
와 g
의 동작은 합성하고, 비용은 +
한 것이 될것이다.
instance Category where
Costful f c1 . Costful g c2 = Costful (f . g) (c1 + c2)
요렇게 말이다.
이때 f . g
의 비용은 함수를 실행하기 전에도 알수있다.
반면 그냥 f
, g
를 모나딕한 함수로 정의하고 f >=> g
이런식으로 합성했을땐, 함수를 실제로 실행하기 전에는 비용을 알수 없다. >=>
또는 >>=
의 정의를 생각해보면 쉽게 알수 있다.
Category
인스턴스는 정적인 정보를 추가로 가지고 있는 함수, 또는 함수보다 표현력이 약한데 비스무리한거(그래서 정적인 정보가 더많은) 것을 다룰때 유용하다.
2022年–2023年 사이에 키우던 강아지랑 어머니, 그리고 아버지께서 次例로 떠나고 나서 憂鬱症으로 到底히 일을 할 수 없을 것 같아서 退社를 했는데, 家族의 葬禮로 因한 憂鬱과 退社로 因한 기쁨이 서로 相殺되어 제로가 된 經驗이 있다.
@hongminhee洪 民憙 (Hong Minhee) 힘내십쇼ㅠㅠ 앞으로 좋은일이 많으셨으면 좋겠네요
https://wikidocs.net/book/14314
Langchain 관련해서 한국어로 정리가 잘 정리되어 있는 듯
하스켈 패키지 검색 엔진이자 웹 서비스인 후글(Hoogle)은 서비스에 종종 문제가 생기곤 합니다. 그럴 때는 다음과 같은 대체 서비스를 이용해보세요!
한편 후글을 로컬에 설치해서 사용하는 것도 가능합니다. 잦은 서비스 문제에 질렸다면 로컬에 후글을 설치해보세요!
그리고 만약 당신이 부자라면⋯ 하스켈 재단에 기부해주세요⋯
우분투에서 뻗어나온 운영체제 이름으로 고군분투 좋은 것 같지 않아? (엉망진창 비난과 핍박을 받는다)
ActivityPub은 눈팅만 하고있었는데, 슈티에 피드를 넣기로 결정하고나니 ActivityPub를 써볼 기회가 생겼다. 따로 페디버스 서버를 팔지, 아니면 다른 방법을 쓸지(있긴 한가)를 고민해봐야한다.
모바일 뷰에서 타임라인 레이아웃이 깨지던 문제를 해결했습니다. 제보해주신 @bglbgl gwyng 님께 감사드립니다!
モバイルビューでタイムラインのレイアウトが崩れる問題を修正しました。報告してくださった @bglbgl gwyng さんに感謝します!
쉘스크립트처럼 oci 컨테이너들을 조합하는 언어가 있으면 좋겠다.
컨테이너는 샌드박싱된 파일시스템을 입력으로 받아 출력으로 쓰고, 그런 컨테이너들을 (|
pipe operator로 stdin/stdout을 잇듯이) 조합하는 것이다. 그리고 이때 각 컨테이너가 필요로하는 입력 파일/디렉토리들에 대해 일종의 타입 체크를 해서 no such file or directory
가 뜨는것을 막아줄수 있을것이다.
사실 yaml등으로 작성하는 CI/CD 설정 파일들이 비슷한 기능을 하고있는데, 이걸 좀더 멀쩡한 언어로, 로컬에서도 쓸수있으면 좋겠다.
@bglbgl gwyng 예전에 Bass라는 언어를 우연히 본 적이 있는데, 그게 떠오르네요. 말씀하신 것과는 좀 다르지만요.
@bglbgl gwyng 예전에 Bass라는 언어를 우연히 본 적이 있는데, 그게 떠오르네요. 말씀하신 것과는 좀 다르지만요.
@hongminhee洪 民憙 (Hong Minhee) 오 제가 원하는 방향인거 같은데요? 감사합니다
쉘스크립트처럼 oci 컨테이너들을 조합하는 언어가 있으면 좋겠다.
컨테이너는 샌드박싱된 파일시스템을 입력으로 받아 출력으로 쓰고, 그런 컨테이너들을 (|
pipe operator로 stdin/stdout을 잇듯이) 조합하는 것이다. 그리고 이때 각 컨테이너가 필요로하는 입력 파일/디렉토리들에 대해 일종의 타입 체크를 해서 no such file or directory
가 뜨는것을 막아줄수 있을것이다.
사실 yaml등으로 작성하는 CI/CD 설정 파일들이 비슷한 기능을 하고있는데, 이걸 좀더 멀쩡한 언어로, 로컬에서도 쓸수있으면 좋겠다.
@bglbgl gwyng nushell 은 또 처음 보네요.
zsh
와 비교해 쓰기 편한지 어떤지 궁금하네요.
@arkjunJuntai Park 저도 시도해볼 여유는 없어서 직접 써보진 못했습니다. 언어가 좀더 멀쩡하고 모던한 느낌은 있어요.
늙은이라 아직도 bash
를 쓰고 있는데, 언젠가 옮기긴 해야겠지만 뭘로 옮겨야 할 지가 고민이다. 진취적으로 @oilsforunix 같은 걸 쓸지, 아니면 여러 애플리케이션의 자동 완성 지원을 고려하여 zsh
같은 걸 쓰는 게 좋을지… 중간점에 있는 fish
같은 게 적절할까 싶기도 하다.
@hongminhee洪 民憙 (Hong Minhee) nushell은 어떨까요?
https://github.com/bglgwyng/semantic-lang-gen
I wrote(tbh, just packaged) a Haskell library that generates TreeSitter bindings and the corresponding AST type definition from TreeSitter language definition. Writing parsers using a parser combinator is fun, of course. However, with TreeSitter, you can eat free lunches of language tooling.
프로그래밍 언어 하스켈 패키지 중에 연합우주와 관련 있는 것을 찾아봤더니 webfinger-client
가 있습니다. 2016년에 마지막 업로드가 되었고 너무 오래 돼서 빌드도 안 되는 상태입니다. LLM 도움을 받아 빌드 가능하게 패치하고 메인테이너에게 연락을 해봤습니다. 답장은 아직 없고 사실 메일을 보낸 지 24시간이 지나지도 않았지만 왠지 연락이 오지 않을 것만 같습니다. 급한 마음에(왜 급한지 모르겠지만) 하스켈 포럼에 패키지를 인수하고 싶다고 글을 남겼습니다. 좋은 소식이 오길 기대해봅니다.
https://discourse.haskell.org/t/taking-over-the-webfinger-client-package-maintenance/11628
Hackers' Pub에 만들어야 할 게 너무 많아서 우선순위 설정이 어렵다. (ADHD가 원래 이런 거 어려워 한다고 합니다.)
- 알림 (멘션이나 DM, 댓글, 공유 같은 거 모아서 보여주는 기능)
- 환경 설정 (UI 언어 설정 등)
- RSS
- 좋아요 또는 에모지 리액션 (이 두 기능을 어떻게 조화시킬지 계속 고민하고 있음)
- 해시태그
- 알고리즘 타임라인 (팔로하지 않아도 관심 있을 만한 콘텐츠는 타임라인에 함께 나오게)
- 설문조사 (ActivityPub의
Question
) - 중국어 번역 추가 (다른 것보다 행동 강령을 어떻게 번역해야 할 지 막막…)
이거 말고도 당장 생각은 안 나는데 뭔가 많음…
@hongminhee洪 民憙 (Hong Minhee) 요건 사소한 부분인데, 어제 해커스펍을 몇분께 소개했는데 회원가입에서 막혀있습니다. 관리자에게 연락하라고 되어있는데 그 방법도 소개되어있지 않아요.
bgl gwyng replied to the below article:
Hackers' Pub에서 DOT 언어(Graphviz)로 다이어그램 그리기

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub
Hackers' Pub에 숨겨진 유용한 기능, 바로 Graphviz DOT 언어 지원에 대해 알아봅니다. 이 기능을 사용하면 복잡한 다이어그램을 간단하게 Markdown 코드 블록 안에 DOT 언어로 기술하여 표현할 수 있습니다. 특히 `graphviz` 언어 태그를 사용하여 ActivityStreams 데이터 전송 과정을 시각적으로 나타낼 수 있습니다. 서버 간의 상호작용을 명확하게 보여주는 다이어그램을 통해, 독자는 Mastodon과 Hackers' Pub 서버 간의 데이터 흐름을 쉽게 이해할 수 있습니다. 이 기능은 긴 게시글뿐만 아니라 짧은 글에서도 유용하게 활용될 수 있으며, 기술적인 내용을 시각적으로 표현하고자 하는 사용자에게 큰 도움이 될 것입니다.
Read more →와우 카테고리 이론 공부하고있는 내용들을 공유하고 싶었는데 딱 좋네요
나는 모나드를 설명하기가 어려운게 그냥 대부분의 언어에서 (HKT의 부재로) Monad
를 정의를 못해서라고 생각한다.
Haskell에 대한 경험이 없는 친구들한테 모나드를 설명하면 잘 알아듣는다. 근데 끝나고 그게 그럼 클래스냐 디자인 패턴이냐 이런 질문이 이어진다.
자기가 쓰고있는 언어에서 어떻게 쓸수있는지를 묻는셈인데, 여기서 '굳이 따지면 디자인패턴 같은거다' 라고하면 실망하는게 느껴졌다.
같은 이유로, Haskell 사용자에게 카테고리 이론의 유용함을 설명하고싶다면 Category
인스턴스의 활용부터 시작하는게 맞다고 생각한다.
어느 디자인 포트폴리오 회사에서 GIF 지원을 중단하고 WebP 만을 사용하게 강제하면서, 주변 지인이 CLI로 변환하는 불편을 겪고 있었기 때문에 간단한 웹 앱을 만들었습니다. 이전에 동작은 만들었었는데 테마나 스타일링이나 조금 덧 붙여서 공개했습니다.
서버에 GIF 파일을 보내고 다시 받는 대신, 브라우저에서 변환하여 다운받을 수 있습니다.
저는 얼굴인식 카메라 앱 슈티를 개발하고 있습니다 iOS 버전 링크, 안드로이드 버전 링크
세션 타입 좋습니다 여러분