6

PureScript by Example, in the section The Eff Monad -> Handlers and Actions states that "[an effect] handler usually subtracts effects from the set". However, the examples are rather opaque and I can't work out how to write my own handler to achieve this.

Specifically, I'm working with purescript-aff and purescript-affjax. I'd like to use runAff (from purescript-aff) in combination with get (from purescript-affjax).

The problem is that get uses the Affjax monad, whereas runAff expects something using the Aff monad.

Affjax is defined as:

type Affjax e a = Aff (ajax :: AJAX | e) (AffjaxResponse a)

Aff is defined as:

foreign import data Aff :: # ! -> * -> *

I, therefore, want to write a function that has the following type:

Affjax e a -> Aff e a

This seems to me to require a handler that subtracts the ajax part of the effect set. How would one code such a handler?

Attempting to pattern-match, as below, of course results in the error unexpected |.

handleAffjax :: Affjax e a -> Aff e a
handleAffjax (Aff ( | eff1 ) resp1) = Aff eff1 resp1

Thanks all.

Update

Inspired by @christoph-hegemann's answer below, I was able to track down most of the issues with my code.

I think the answer to the question in the title is that one does not subtract an effect from the set, and that description is a little confusing. The effect remains after you've handled it.

The intuition I was missing is that I have to add the expected effects to the calling function type. The lack of a type declaration on main hid that to some extent. I worked it out when I turned Christoph's example into the following compiling example:

module Main where

import Debug.Trace
import Network.HTTP.Affjax
import Control.Monad.Aff
import Control.Monad.Eff
import Control.Monad.Eff.Exception

initialUrl :: URL
initialUrl = "http://127.0.0.1:8000/api/v1/navitem/2/"

runGet :: forall e. Eff (ajax :: AJAX, trace :: Trace | e) Unit
runGet = runAff errorHandler successHandler (get initialUrl)

errorHandler :: forall e. Error -> Eff (trace :: Trace | e) Unit
errorHandler err = print err

successHandler :: forall e. AffjaxResponse String -> Eff (trace :: Trace | e) Unit
successHandler res = print res.response

main = runGet
4

1 に答える 1

5

一歩ずつ進めていきます^^

問題は、get が Affjax モナドを使用しているのに対し、runAff は Aff モナドを使用して何かを期待していることです。

Affjax は次のように定義されます。

type Affjax e a = Aff (ajax :: AJAX | e) (AffjaxResponse a)

Affjax は型シノニムです。これは、Affjax が独自のモナドではなく、Aff モナドの特殊なケースであることを意味します。次にそれを見てみましょう。

Aff は次のように定義されます。

foreign import data Aff :: # ! -> * -> *

つまり、Aff は2 つの型を引数として取り、新しい型を生成する型コンストラクタです。最初の引数の種類は # ! これは次のことを示しています。

  • # -> 行です ...
  • ! -> ... エフェクトで構成されています

したがって、Affjax 型シノニムの定義を見ると、Aff 型コンストラクターへの最初の引数が効果を含むがajax :: Ajax拡張用に開いている効果の行であることがわかります| e

Aff の 2 番目の引数は、Affjax の場合は型変数 a によってパラメーター化された AffjaxResponse の単なる型です。

Pursuitを見ると、AffjaxResponse は単なるレコードの型シノニムであるため、ドット演算子を使用してそのメンバーにアクセスできることがわかります。

始めるための最小限のコンパイル例をまとめました。

module Main where

import Debug.Trace
import Network.HTTP.Affjax
import Control.Monad.Aff
import Control.Monad.Eff
import Control.Monad.Eff.Exception

errorHandler :: forall e. Error -> Eff (trace :: Trace | e) Unit
errorHandler err = print err

successHandler :: forall e. AffjaxResponse String -> Eff (trace :: Trace | e) Unit
successHandler res = print res.response

main = runAff errorHandler successHandler (get "http://www.myApi.com/api" )
于 2015-06-07T19:25:23.450 に答える