대부분의 일상적인 프로그래밍 작업에 Monass 및 Applicative Functors와 같은 Haskell의 고급 개념이 얼마나 중요합니까?


16

나는 그들이 당신에게 Monads와 Just a와 같은 것들을 소개 할 때까지 Haskell Learn 책을 읽었습니다. 이것들은 나에게 반 직관적이므로 배우려고 노력하는 것을 포기하는 것처럼 느낍니다.

그러나 나는 정말로 시도하고 싶다.

나는 적어도 고급 개념을 잠시 피하고 언어의 다른 부분을 사용하여 Haskell의 더 기본적인 부분, 즉 기능, 표준 IO, 파일 처리, 데이터베이스 인터페이스 등.

이것이 하스켈 사용법을 배우는 데 합리적인 접근입니까?


2
당신이 얼마나 멀리 갈지 모르겠습니다. 모나드가 없으면 Haskell에서 유용한 어떤 것도 할 수 없습니다. 프로그래밍에서 유용한 것을 수행하려면 (누군가 실제로 사용하고 싶은 심각한 프로그램 작성과 같이) I / O와 상태가 필요하기 때문에 Haskell에서만 관리 할 수 ​​있습니다. 모나드 사용을 통해.
메이슨 휠러

1
@dan-마침내 Haskell 모나드가 두 문서를 읽음으로써 "모나드를 발명했을 수 있습니다"와 "어색한 분대 태클"을 알았습니다. 나는 그들이 읽지 않은 "당신에게 Haskell을 배우십시오"보다 낫다고 말할 수는 없지만 그들은 나를 위해 일했습니다. IO 모나드와 함께 do 표기법을 사용하려면 모나드가 무엇인지 거의 이해하지 못합니다. 전문가를 웃게하거나 울게 만들지 만, 피상적으로는 사용과 크게 다르지 않은 일을 할 것입니다 전통적인 명령형 언어. 그러나 더 깊이 이해 하는 것이 가치가 있습니다.
Steve314

2
@dan, OOP에 지루해하고 기능적 언어에 대해 감사하고 궁금해하기 시작하는 데 거의 10 년이 걸렸습니다. Haskell에게 진지한 시도를하기 전에 나는 여전히 F #과 Clojure를 배울 것입니다. 개인적인 도전은 훌륭하지만, 장의 느낌과 저항이 가장 적은 경로에 대해 할 말이 있습니다. 당신이 누군지에 따라 다릅니다. 강력한 수학 유형이라면 처음부터 Haskell / Schem을 원할 것입니다. 당신이 더 많은 일을한다면, 괜찮습니다. 하스켈에게 '행하거나 죽는'태도로 접근하지 마십시오. 계속해서 다른 것들을 배우고 지루할 때 돌아옵니다.
Job

조언 @Job에 감사드립니다. Clojure를 조금 사용해 보았지만 Lisp 구문은 실제로 읽기와 입력 모두에서 작동하지 않습니다. Haskell의 구문이 더 자연 스럽다는 것을 알았습니다. 그동안 프로젝트에 루비를 사용하게되어 기쁘지만 Haskell에서 실용적인 프로젝트를 시작하려고합니다.
dan

@ dan, Funny, Clojure의 구문이 다소 우호적이라고 생각하지만 아마도 이전에 Scheme에 노출 되었기 때문일 것입니다. F # 이후에 Haskell이하는 방식에 익숙해 질 것입니다.
Job

답변:


16

먼저 추상적 개념 학습과 구체적인 개념 학습을 구별 해 봅시다 .

당신은 그들이 완전히 유비쿼터스라는 단순한 이유 때문에 모든 특정 예제를 무시하지 않을 것입니다. 실제로 추상화 는 특정 예제를 사용하여 수행 할 작업을 통합 하기 때문에 대부분 존재합니다 .

반면 추상화 자체는 확실히 유용 하지만 즉시 필요한 것은 아닙니다. 추상화를 완전히 무시하고 다양한 유형을 직접 사용하여 얻을 수 있습니다. 당신은 그것들을 결국 이해하고 싶을 것이지만, 나중에 다시 돌아올 수 있습니다. 사실, 당신이 그렇게한다면, 당신이 그것으로 돌아 왔을 때 이마를 때리고 왜 당신이 편리한 범용 도구를 사용하는 대신 왜 힘든 일을했는지 ​​궁금해 할 것입니다.

가지고 Maybe a예를 들어. 데이터 유형일뿐입니다.

data Maybe a = Just a | Nothing

자체 문서화를 제외한 모든 것입니다. 선택적 값입니다. 유형이 "그냥" a있거나 아무 것도 없습니다. 존재하지 않을 수 Maybe String있는 String값을 찾기 위해 반환 하는 일종의 조회 기능이 있다고 가정 해보십시오 . 따라서 값에 패턴 일치를 지정하여 값이 무엇인지 확인하십시오.

case lookupFunc key of
    Just val -> ...
    Nothing  -> ...

그게 다야!

실제로 필요한 것은 없습니다. Functors 또는 Monads 또는 다른 것 없음 . 그것들은 Maybe a값 을 사용하는 일반적인 방법을 표현 하지만 ... "디자인 패턴"이라는 관용구입니다.

당신이 정말로 그것을 완전히 피할 수없는 곳은입니다 IO. 그러나 그것은 어쨌든 신비한 블랙 박스이므로 그것이 무엇인지 Monad또는 무엇을 의미하는지 이해하려고 노력할 가치가 없습니다 .

사실, 여기 당신 IO 지금 정말로 알아야 할 모든 것에 대한 치트 시트 가 있습니다 :

  • 무언가가 type IO a인 경우 이는 무언가를 수행 하고 a가치를 내뿜는 절차 임을 의미합니다 .

  • do표기법을 사용하여 코드 블록 이 있으면 다음과 같이 작성하십시오.

    do -- ...
       inp <- getLine
       -- etc...
    

    ... 의 오른쪽 에서 프로 시저실행하고<- 결과를 왼쪽의 이름에 지정합니다.

  • 이와 같은 것이 있다면 :

    do -- ...
       let x = [foo, bar]
       -- etc...
    

    ...의 오른쪽에 일반 표현식 (프로 시저가 아님)의 값을 =왼쪽의 이름에 할당하는 것을 의미합니다 .

  • 다음과 같이 값을 할당하지 않고 무언가를 넣는 경우 :

    do putStrLn "blah blah, fishcakes"
    

    ... 프로 시저를 실행하고 반환하는 것은 무시한다는 의미입니다. 일부 절차는 유형이 IO ()고마웠다 ()만이 절차를 의미한다 무언가를하고 값을 반환하지 않습니다 그래서, 유형 분류 아무 말도하지 않는 자리의입니다. void다른 언어 의 함수 와 비슷합니다 .

  • 동일한 절차를 두 번 이상 실행하면 다른 결과를 얻을 수 있습니다. 그것은 일종의 아이디어입니다. 이것이 IO값에서 "제거"하는 방법 IO이없는 이유입니다. 어떤 것이 값이 아니기 때문에 값을 얻는 절차입니다.

  • do블록 의 마지막 행은 할당이없는 일반 프로 시저 여야합니다. 여기서 해당 프로 시저의 반환 값은 전체 블록의 반환 값이됩니다. 반환 값에 이미 할당 된 일부 값을 사용하려면이 return함수는 일반 값을 사용하여 해당 값을 반환하는 비 작동 절차를 제공합니다.

  • 그 외에는 특별한 것이 없습니다 IO. 이러한 절차는 실제로는 평범한 값이므로 다른 방법으로 전달하여 결합 할 수 있습니다. 그들이 무언가를 do함으로써 어딘가에 있는 블록 에서 실행될 때만 가능 main합니다.

따라서 완전히 지루하고 틀에 박힌 전형적인 프로그램과 같은 것에서 :

hello = do putStrLn "What's your name?"
           name <- getLine
           let msg = "Hi, " ++ name ++ "!"
           putStrLn msg
           return name

... 당신은 명령형 프로그램처럼 그것을 읽을 수 있습니다. 우리는라는 절차를 정의하고 있습니다 hello. 실행되면 먼저 이름을 묻는 메시지를 인쇄하는 절차를 실행합니다. 다음으로 입력 줄을 읽고 결과를 할당하는 프로 시저를 실행합니다 name. 그런 다음 이름에 표현식을 할당합니다 msg. 그런 다음 메시지를 인쇄합니다. 그런 다음 전체 블록의 결과로 사용자 이름을 반환합니다. 이후 nameA는 String,이 수단 hello리턴한다이다가 절차 String, 그래서이 유형이가 IO String. 이제이 절차를 실행하는 것처럼 다른 곳에서이 절차를 실행할 수 있습니다 getLine.

Pfff, 모나드 누가 필요합니까?


2
@ dan : 천만에요! 도중에 특정 질문이 있으면 주저하지 말고 스택 오버플로를 요청하십시오. [haskell] 태그는 일반적으로 꽤 활동적이며 사람들이 어디에서 왔는지 설명하면 단순한 답을 던지기보다는 이해를 도울 수 있습니다.
CA McCann

9

대부분의 일상적인 프로그래밍 작업에 Monass 및 Applicative Functors와 같은 Haskell의 고급 개념이 얼마나 중요합니까?

그들은 필수적입니다. 그것들이 없으면 Haskell을 다른 명령형 언어로 사용하기가 너무 쉽습니다. Simon Peyton Jones는 한때 "세계 최고의 명령형 프로그래밍 언어"인 Haskell을 불렀지 만 여전히 최고의 부분을 놓치고 있습니다.

Monads, Monad Transforms, Monoids, Functors, Applicative Functors, Contravarient Functors, Arrows, Categories 등은 디자인 패턴입니다. 일단 당신이 만드는 것 중 하나에 특정한 것을 맞추면, 추상적으로 쓰여진 방대한 기능을 활용할 수 있습니다. 이 유형 클래스는 단순히 당신을 혼란스럽게하는 것이 아니라 인생을 더 쉽게하고 생산성을 높이기 위해 있습니다. 제 생각에는 좋은 하스켈 코드의 간결함에 대한 가장 큰 이유입니다.


1
+1 : "Monads, Monad Transforms, Monoids, Functors, Applicative Functors, Contravarient Functors, Arrows, Categories 등은 디자인 패턴입니다." !
Giorgio

7

무언가를 실행하고 싶다면 엄격히 필요합니까? 아니.

아름다운 관용적 Haskell 프로그램을 작성하려면 필요합니까? 물론.

Haskell에서 프로그래밍 할 때 다음 두 가지 사항을 명심하십시오.

  1. 타입 시스템이 도움이됩니다. 매우 다형적인 typeclass-heavy 코드로 프로그램을 작성 하면 원하는 함수의 유형이 (단일!) 올바른 구현으로 안내 하는 멋진 상황에 처할 수 있습니다 .

  2. 사용 가능한 다양한 라이브러리는 원칙 # 1을 사용하여 개발되었습니다.

따라서 Haskell에서 프로그램을 작성할 때 유형을 작성하는 것으로 시작합니다. 그런 다음 다시 시작하여 좀 더 일반적인 유형을 작성하십시오 (그리고 기존 유형 클래스의 인스턴스가 될 수 있다면 더 좋습니다). 그런 다음 원하는 유형의 값을 얻는 함수를 작성합니다. (그런 다음에 그것들을 가지고 놀면서 ghciquickCheck 테스트를 작성할 수도 있습니다.) 그리고 마지막으로에 모두 붙입니다 main.

무언가를 실행시키는 추악한 Haskell을 작성할 수 있습니다. 그러나 일단 그 단계에 도달하면 배울 것이 훨씬 더 많습니다.

행운을 빕니다!


1
감사합니다! Clojure와 Haskell 사이에서 흔들리고 있었지만 이제는 여러분과 같은 사람들이 얼마나 도움이 되었는가에 따라 Haskell을 향해 기울고 있습니다.
dan

1
Haskell 커뮤니티는 매우 친절하고 도움이되는 것 같습니다. 그리고 흥미있는 많은 아이디어가 어디에서 온 것 같다
재커리 K
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.