2017-10-13 19 views
9

예 :으로 Purescript를 읽었으며 리더 모나드를 소개하는 부분에 도달했습니다. 이 예는 다음과 같습니다 :리더 모나드 이해

createUser :: Reader Permissions (Maybe User) 
createUser = do 
    permissions <- ask 
    if hasPermission "admin" permissions 
    then map Just newUser 
    else pure Nothing 

나를위한 혼란스러운 부분은 ask 기능입니다. 서명은 다음과 같습니다 그것은 내가 State 모나드에 대해 읽고 있었다 허공

에서 독자를 생성 것처럼 나타납니다

ask :: forall r. Reader r r 

, 그것의 get 기능과 동일한 개념을 가지고 있었다. 텍스트 설명 :

상태는 상태 모나드의 데이터 생성자에 의해 숨겨진 함수 인수로 구현되므로 주위를 통과 할 명시 적 참조가 없습니다.

나는 이것이 핵심입니다 추측하고있어,와 같은 일이 리더로 여기에 무슨 일이 일어나고 있지만, 그것이 어떻게 작동하는지 이해가 안 ...

위의 예제를 실행하면 runReader 방법을 통해 제공된 값이 ask의 결과로 갑자기 나타 납니까? ask에 대한 하스켈 문서 : 모나드 환경을 검색합니다.하지만 내 혼란은 에서 어디입니까? 내가 보는 방식으로, 값이 runReader으로 전달되고, 어딘가에이 저장되고, 얻으려면 ask이라고 부릅니다.하지만 그건 의미가 없습니다.

예제가 Purescript인데, 하스켈의 지식이있는 사람도 대답 할 수 있다고 추측하고 있습니다. 따라서 하스켈 태그도 대답 할 수 있습니다.

+2

'리더 b'는의'래퍼입니다 -> b'. 그래서'ask :: forall a. Reader a는 궁극적으로'forall a 유형의 값입니다. a -> a', 주위에 래퍼가 있습니다. –

답변

8

필자는 현재 PureScript 환경이 주위에 없기 때문에 하스켈의 관점에서 대답하려고 노력하고 도움이되기를 바랍니다.

리더 정말 함수 주위 만 '래퍼', 그래서 당신이 Reader r r을 얻을 때, 당신은 정말에만 rr까지 독자를 얻을; 즉, 함수 r -> r. 당신은 플라톤 주의자라면, 나는 그들이 항상 가정 존재하기 때문에

는 는

당신은

당신이 do 표기법을 사용하는 경우, 당신은 '모나드 안에'있어 ..., 허공 기능을 소환 할 수 따라서 컨텍스트 r은 암시 적입니다. 즉, r 값을 반환하는 함수를 호출하고 <- 화살표를 사용하면 해당 컨텍스트를 얻을 수 있습니다.

+2

Upvoted. 아마도 'r -> r'함수를 얇은 공기에서 소환하는 방법은 아마도 'id'라는 주문을 사용하는 것일 것입니다. (그리고 id는 파라 메 트릭 덕분에 _only_와 같은 함수입니다.) –

+0

제 경우에는 Reader가 퍼미션 -> 아마 사용자 인 래퍼입니다. 'runReader createUser permissions'를 실행하면'createUser'의 본문에서'ask'가'runReader'에 전달한 것과 동일한'permission'을 반환하는 것을 어떻게 알 수 있습니까? 나는이 모든 것을 잘못보고있는 것처럼 질문이 완전히 무의미하다는 것을 확신합니다. 그러나 제 뇌를 풀어 주도록 도와주세요. – kaqqao

+1

@kaqqao''Reader Permissions (Maybe User)'타입은'Permissions -> (Maybe User)'에 대한 래퍼 일 뿐이므로'createUser' '값'은 실제로 함수입니다 (그러나 함수는 값이므로 멋지다). 'runReader'를 호출 할 때,'createUser'뿐만 아니라'r'의 값도 전달해야합니다 -이 경우에는'Permissions' 값입니다. 'runReader'는 전달한'Permissions' 값으로 래핑 된 함수를 호출합니다. HTH. –

1

몇 가지 대체를 수행하면 효과가 있다는 것을 확신 할 수 있습니다. 먼저 createUser의 서명을보십시오. 이제 Reader의 정의를 "풀다"하자

createUser :: Reader Permissions (Maybe User) 
{- definition of Reader -} 
createUser :: ReaderT Permissions Identity (Maybe User) 

ReaderT 유형은 하나의 데이터 생성자가 있습니다 ReaderT (r -> m a) 입력 ReaderT (Permissions -> Identity (Maybe User))의 값으로 평가되는 용어입니다 createUser을 의미한다. 보시다시피, 그것은 단지 ReaderT 태그가 붙은 함수입니다.얇은 공기에서 아무것도 만들 필요가 없지만 해당 함수가 호출 될 때 Permissions 유형의 값을받습니다.

이제 문제가있는 라인을 살펴 보겠습니다. 당신은 do 표기 그냥 문법 설탕, 그리고 표현임을 알고

do permissions <- ask 
    if hasPermission "admin" permissions 
    then map Just newUser 
    else pure Nothing 

desugars

ask >>= \permissions -> 
    if hasPermission "admin" permissions 
    then map Just newUser 
    else pure Nothing 

이가 무엇을 이해하려면, 당신은 ask, >>=pure의 정의를 조회해야합니다 ReaderT입니다. 의는 대체의 또 다른 라운드를 수행 할 수 있습니다 :

ask >>= \permissions -> ... 
{- definition of ask for ReaderT -} 
ReaderT pure >>= \permissions -> ... 
{- definition of >>= for ReaderT -} 
ReaderT \r -> 
    pure r >>= \a -> case (\permissions -> ...) a of ReaderT f -> f r 
{- function application -} 
ReaderT \r -> 
    pure r >>= \a -> 
    case (if hasPermission "admin" a 
      then map Just newUser 
      else pure Nothing) of ReaderT f -> f r 
{- definition of pure for Identity -} 
ReaderT \r -> 
    Identity r >>= \a -> 
    case (if hasPermission "admin" a 
      then map Just newUser 
      else pure Nothing) of ReaderT f -> f r 
{- definition of >>= for Identity -} 
ReaderT \r -> 
    (\a -> 
    case (if hasPermission "admin" a 
      then map Just newUser 
      else pure Nothing) of ReaderT f -> f r) r 
{- function application -} 
ReaderT \r -> 
    case (if hasPermission "admin" r 
     then map Just newUser 
     else pure Nothing) of ReaderT f -> f r 

당신이 볼 수 있듯이, createUser이 명확하게 표현을 통해 값 (이하 "환경") 스레드 ReaderT 래핑 단지 기능입니다. runReader 함수를 랩핑 해제하고 제공된 인수를 호출

runReader :: forall r a. Reader r a -> r -> a 
runReader (ReaderT f) r = f r