Sure. Have a look at this complete and compiling example:
1. Example
import Prelude
import Effect.Aff (Aff)
import Effect.Class.Console (log)
import Effect.Class.Console as Eff
import Node.Encoding (Encoding(..))
import Node.FS.Aff as FSA
import Node.FS.Sync as FS
type Env m =
{ readFile :: String -> m String
, writeFile :: String -> String -> m Unit
, log :: String -> m Unit
}
mkEnvAff :: Aff (Env Aff)
mkEnvAff = do
log "Creating the env..."
pure
{ readFile: \path -> FSA.readTextFile UTF8 path
, writeFile: \path content -> FSA.writeTextFile UTF8 path content
, log: \msg -> Eff.log msg
}
Let’s assume I make a mistake and implement writeFile
like:
\path content -> FS.writeTextFile UTF8 path content
(uses Effect
instead of Aff
)
Then the compilation error is not right in the place where the mistake happend, but instead in the line log "Creating the env..."
2. Example Refactored with Current PureScript
So what I need is better inference and one simple and way to get it is to provide more type signatures. So if my Env
is growing I’d like to avoid those inaccurate compiler message (positions) and do the following refactor:
type Env m =
{ readFile :: Env_readFile m
, writeFile :: Env_writeFile m
, log :: Env_log m
}
type Env_readFile m = String -> m String
type Env_writeFile m = String -> String -> m Unit
type Env_log m = String -> m Unit
mkEnvAff :: Aff (Env Aff)
mkEnvAff = do
log "Creating the env..."
let
readFile :: Env_readFile Aff
readFile path = FSA.readTextFile UTF8 path
writeFile :: Env_writeFile Aff
writeFile path content = FSA.writeTextFile UTF8 path content
log :: Env_log Aff
log msg = Eff.log msg
pure
{ readFile, writeFile, log }
And if I do the mistake from above again, I get the error message right at the place where it occurs. However the types now need the boilerplate of defining each field in a separate type alias.
3. Example Refactored with the Proposal
So with the Indexed Access Type
the whole example would look like:
type Env m =
{ readFile :: String -> m String
, writeFile :: String -> String -> m Unit
, log :: String -> m Unit
}
mkEnvAff :: Aff (Env Aff)
mkEnvAff = do
log "Creating the env..."
let
readFile :: Env["readFile"] Aff
readFile path = FSA.readTextFile UTF8 path
writeFile :: Env["writeFile"] Aff
writeFile path content = FSA.writeTextFile UTF8 path content
log :: Env["log"] Aff
log msg = Eff.log msg
pure
{ readFile, writeFile, log }
Hope that clarifies a bit how the proposal could be useful.