2017-10-13 8 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のHaskellドキュメントは、次のように言っています。モナド環境を取得します。しかし私の混乱はここから?私がそれを見る方法は、値がrunReaderに渡され、のどこかにが格納され、それを取得する - あなたはaskと呼ぶが、それは意味をなさない。

例はPurescriptですが、私はHaskellの識字者も答えられると考えています。したがって、Haskellタグです。

+2

'Reader a b'は' a - > b 'のラッパーです。だから、 'ask :: forall a。 Reader a a'は最終的に 'forall aの型の値です。 a - > a'、それを囲むラッパーがあります。 –

答えて

8

私は現在、PureScript環境を持っていないので、私はHaskellの観点から答えようとしています。

リーダーは本当に機能の周りだけで「ラッパー」ですので、あなたがReader r rを得るとき、あなたは本当にのみrrからリーダーを取得します。換言すれば、機能r -> rである。

あなたはプラトン主義なら、私は、彼らが常に存在すると仮定し、ので、あなたあなたがdo表記を使用する場合、あなたは「モナドの内側」だ...、空中から

を関数を呼び出すことができますしたがって、コンテキストrは暗黙的です。言い換えれば、rの値を返す関数を呼び出し、<-の矢印を使用すると、そのコンテキストが取得されます。

+2

Upvoted。おそらく、このような「r→r」関数を薄い空気から召喚する方法は、命題「id」を発することではないでしょう。 (そして、 'id'はそのような関数であり、パラメトリック性のためです。) –

+0

私の場合、ReaderはPermissions - > Maybe Userのラッパーです。 'runReader createUser permissions'を実行すると、' createUser'の本体で 'ask'が' runReader'に渡したのと同じ 'permissions'を返すことを知っていますか?私はこれをすべて間違って見ているので、質問は全く無意味であると確信しています...しかし、私の頭脳を解きほぐしてください。 – kaqqao

+1

@kaqqaoタイプ 'Reader Permissions(Maybe User)'は 'Permissions - >(Maybe User)'上の単なるラッパーであるため、 'createUser' '値'全体は実際には関数です(しかし、関数は値です。カッコいい)。 'runReader'を呼び出すときには、' createUser'だけでなく 'r'の値も渡す必要があります - この場合は' Permissions'の値です。 'runReader'はあなたが渡した' Permissions'値でラップされた関数を呼び出します。 HTH。 –

1

いくつかの置換を行うことで効果があると自信を持って確認できます。最初にcreateUserの署名を見てください。

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

ReaderTタイプが1つのデータだけコンストラクタを持っています:ReaderT (r -> m a)createUserはタイプReaderT (Permissions -> Identity (Maybe User))の値に評価用語であることを意味しているのは、Readerの定義を「アンロール」しましょう。ご覧のとおり、それはちょうど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 
関連する問題