Haskell은 기본값으로 단순함을 택하고, 복잡성은 타입을 통해 명시적으로 옵트인하도록 요구한다는 점을 설명한다. 이러한 설계는 코드의 문맥 의존성을 줄이고, 명시적 타입 서명이 타인의 이해와 추론을 돕는다는 논지를 전개한다.
URL: https://www.haskellforall.com/2013/08/sometimes-less-is-more-in-language.html
Title: Sometimes less is more in language design
Haskell for all: Sometimes less is more in language design
===============
Haskell 프로그래머들은 흔히 Haskell 코드가 이해하고 추론하기 쉽다고 말하지만, 그 이유를 자세히 설명하는 경우는 드뭅니다. 그 배경에는 하나의 단순한 원칙이 있습니다: Haskell은 기본적으로 단순합니다(simple by default).
잠깐, 뭐라고요? 우리가 같은 언어를 말하고 있는 걸까요? 모나드와 zygohistomorphic prepromorphisms 같은 게 있는 그 언어 말이죠? 네, 바로 그 Haskell이 맞습니다.
예를 들어, 다음 타입 시그니처는 무엇을 말해 줄까요: x :: Bool 이 타입 시그니처는 x가 불리언 값이라는 것을 말해 줍니다 … 그리고 그게 전부입니다! Haskell의 타입 시그니처는 다른 언어보다 더 강력한데, 그 이유는 값이 무엇이 아닌지도 함께 알려주기 때문입니다:
다시 말해, Haskell에서는 복잡성이 옵트인(opt-in)입니다.
명령형 언어, 객체지향 언어, 그리고 대부분의 다른 함수형 언어들은 Haskell보다 더 복잡한 기준선에서 출발합니다. 이 언어들은 모두 더 많은 내장 장치와 기능을 제공하는 경쟁을 벌이는데, 더 많은 내장 기능이 곧 더 좋다는 전제에서 시작하기 때문입니다.
하지만 문제는 이런 기능을 사용하지 않도록 선택할 수 없고, 호출하는 라이브러리 함수가 이 모든 기능을 사용하지 않는다고 가정할 수도 없다는 점입니다. 그래서 다음과 같은 세심한 문서에 의존해야 하거나:
… 아니면 원본 소스 코드를 꼼꼼히 살펴봐야 합니다.
Haskell은 다른 설계적 절충을 택합니다. 더 단순한 기준선에서 시작해 추가하는 것들을 명시적으로 선언하는 방식이죠. 상태가 필요하다면 타입에 이를 선언해야 합니다: -- 문자열을 계산하기 위해 Int 상태를 읽고 쓴다 stateful :: State Int String 부작용이 필요하다면 타입에 이를 선언해야 합니다: takeMedicine :: IO () -- 이 약이 당신에게 적합한지 의사와 상의하세요 값이 널일 수 있어야 한다면 타입에 이를 선언해야 합니다: toBeOrNotToBe :: Maybe Be -- 그것이 문제로다 타입에 반영되지 않는 것도 몇 가지 있습니다. 예를 들면 게으름(laziness)과 체크되지 않는 예외입니다. 예상할 수 있듯이, 이 둘은 Haskell을 사용할 때 사람들이 자주 불평하는 내장 기능이기도 합니다.
기술적으로는, Haskell에는 타입 추론이 있으므로 이런 타입 시그니처를 모두 생략할 수 있습니다. 번거로움을 싫어하고 그냥 코드를 빠르게 작성하고 싶다면 시그니처를 생략해도 컴파일러가 뒤에서 모든 타입을 처리해 줄 것입니다.
하지만 다른 사람과 코드를 공유할 때는 명시적인 타입 시그니처를 추가하는 것이 좋습니다. 이 타입 시그니처들은 코드를 읽는 사람의 마음가짐을 준비시켜 주는데, 각 함수에 대해 이해하는 데 필요한 문맥의 범위를 단단히 제한해 주기 때문입니다. 코드가 요구하는 문맥이 적을수록, 다른 사람들이 그 코드를 고립된 상태에서 더 쉽게 추론할 수 있습니다.
Posted by Gabriella Gonzalez at 7:33 AM
Email ThisBlogThis!X에 공유Facebook에 공유Pinterest에 공유
Franklin Chen2013년 8월 2일 오전 9:14
대체로 동의하지만, Haskell이 기본적으로 다른 언어보다 덜 제공한다는 말이 전적으로 사실인 것은 아닙니다.예를 들어, "x :: Bool"은 다른 언어에서 보통 이해되는 것처럼 x가 불리언이라고 말하지 않습니다. Bool은 게으른 불리언입니다. "x = undefined"로 두었다가, 프로그램을 한참 실행한 후에야 의도치 않게 크래시하게 만들었음을 알아차릴 수도 있습니다.
또한, 게으른 평가 때문에 시간과 공간 사용량에 대해 추론하기가 더 어려워집니다.
Haskell은 다른 언어들이 선택한 것과는 다른 몇 가지 절충을 선택했습니다.
(그리고 unsafePerformIO도 있습니다.)
1.  [Gabriella Gonzalez](https://www.blogger.com/profile/01917800488530923694)[2013년 8월 2일 오전 9:17](https://www.haskellforall.com/2013/08/sometimes-less-is-more-in-language.html?showComment=1375460231861#c1411878925992256050)
동의합니다, 특히 게으름에 대해서요. 그래도 이것은 이 글의 전제를 지지합니다. Haskell이 타입에 반영하지 않는 부분이야말로 사람들이 가장 많이 불평하는 부분이니까요:
예외(특히 비동기 예외)
게으름(laziness)
반칙(unsafePerformIO)
균형을 위해 본문에 이 점을 반영해 보겠습니다.
[Reply](javascript:;)
2.  [mightybyte](https://www.blogger.com/profile/15198998578494149797)[2013년 8월 3일 오후 12:09](https://www.haskellforall.com/2013/08/sometimes-less-is-more-in-language.html?showComment=1375556999612#c3537132167942990113)
과거에는 unsafePerformIO 문제가 저도 거슬렸습니다. 하지만 이제는 SafeHaskell이 이 문제를 다룹니다.
어쩌면 Haskell에서의 undefined를 다른 언어의 널 포인터에 해당한다고 주장할 수도 있겠습니다. 차이는, 널 포인터는 버그 없는 정상 동작의 일부로도 사용되지만 Haskell의 undefined는 그렇지 않다는 점입니다.
게으름으로 인한 시간과 공간 사용량은, 제 생각에는 우리가 무엇에 익숙한가에 크게 좌우되는 문제입니다.
[Reply](javascript:;)
Anonymous2013년 8월 4일 오전 8:40
http://axisofeval.blogspot.com/2011/01/why-lisp-is-big-hack-and-haskell-is.html이 주제를 Common Lisp과 대비해 다루고 있는 글입니다.
[Reply](javascript:;)
구독: 게시글 댓글(Atom)
이 작품은 크리에이티브 커먼즈 저작자표시 4.0 국제 라이선스에 따라 이용할 수 있습니다. Simple 테마. Blogger가 제공.