haskell - Access environment in a function -


in main can read config file, , supply runreader (somefunc) myenv fine. somefunc doesn't need access myenv reader supplies, nor next couple in chain. function needs myenv tiny leaf function.

how access environment in function without tagging intervening functions (reader env)? can't right because otherwise you'd pass myenv around in first place. , passing unused parameters through multiple levels of functions ugly (isn't it?).

there plenty of examples can find on net seem have 1 level between runreader , accessing environment.


i'm accepting chris taylor's because it's thorough , can see being useful others. heatsink 1 attempted directly answer question.

for test app in question i'll ditch reader altogether , pass environment around. doesn't buy me anything.

i must i'm still puzzled idea providing static data function h changes not type signature of g calls , f calls g. though actual types , computations involved unchanged. seems implementation details leaking on code no real benefit.

you do give return type of reader env a, although isn't bad think. reason needs tag if f depends on environment:

type env = int  f :: int -> reader int int f x =   env <- ask   return (x + env) 

and g calls f:

g x =   y <- f x   return (x + y) 

then g depends on environment - value bound in line y <- f x can different, depending on environment passed in, appropriate type g is

g :: int -> reader int int 

this thing! type system forcing explicitly recognise places functions depend on global environment. can save typing pain defining shortcut phrase reader int:

type global = reader int 

so type annotations are:

f, g :: int -> global int 

which little more readable.


the alternative explicitly pass environment around of functions:

f :: env -> int -> int f env x = x + env  g :: env -> int -> int g x = x + (f env x) 

this can work, , in fact syntax-wise it's not worse using reader monad. difficulty comes when want extend semantics. depend on having updatable state of type int counts function applications. have change functions to:

type counter = int  f :: env -> counter -> int -> (int, counter) f env counter x = (x + env, counter + 1)  g :: env -> counter -> int -> (int, counter) g env counter x = let (y, newcounter) = f env counter x                   in (x + y, newcounter + 1) 

which decidedly less pleasant. on other hand, if taking monadic approach, redefine

type global = readert env (state counter) 

the old definitions of f , g continue work without trouble. update them have application-counting semantics, change them to

f :: int -> global int f x =   modify (+1)   env <- ask   return (x + env)  g :: int -> global int g x =   modify(+1)   y <- f x   return (x + y) 

and work perfectly. compare 2 methods:

  • explicitly passing environment , state required complete rewrite when wanted add new functionality our program.

  • using monadic interface required change of 3 lines - , program continued work after had changed first line, meaning refactoring incrementally (and test after each change) reduces likelihood refactor introduces new bugs.


Comments

Popular posts from this blog

c# - SVN Error : "svnadmin: E205000: Too many arguments" -

c# - Copy ObservableCollection to another ObservableCollection -

All overlapping substrings matching a java regex -