I am writing a framework, where the main function asks user about the function of type a -> [b]
.
However, because that function can be quite complex, its implementation can often look like this:
fn a = extractPartOfAAndConvert a ++ extractAnotherPartofAAndConvert a
That's why I figured using Reader
might be a nice, idiomatic idea to fight that. However, at the same time I realize that some people might not want to use a monad.
While experimenting, I've crafted this solution:
class Iso a b where
isoFrom :: a -> b
isoTo :: b -> a
instance Iso a a where
isoFrom = id
isoTo = id
instance Iso (a -> b) (Reader a b) where
isoFrom f = reader f
isoTo m = runReader m
Which in turn allows me to do:
testCallback :: MyState -> Callback -> MyState
testCallback myState cb = cb myState
-- The important signature
testCallbackGeneric :: Iso Callback a => MyState -> a -> MyState
testCallbackGeneric myState cb = (isoTo cb) myState
callbackFunction :: Callback
callbackFunction s = s + 10
callbackMonad :: Reader MyState MyState
callbackMonad = do
x <- ask
return $ x - 10
-----------
let myStateA = testCallback myState callbackFunction
-- let myStateB = testCallback myState callbackMonad -- won't work, obviously
let myStateC = testCallbackGeneric myState callbackFunction
let myStateD = testCallbackGeneric myState callbackMonad
However, I feel very much like I'm reinventing the wheel.
Is there a way to express the equivalence of Reader to easily write such generic functions without resorting to creating my own type class?
To convert the input, there are a variety of functions that you can use: strtoll , to convert a string into an integer. strtof / d / ld , to convert a string into a floating-point number. sscanf , which is not as bad as simply using scanf , although it does have most of the downfalls mentioned below.
To check for a string, we use hasNextLine(). Similarly, to check for a single character, we use hasNext().
The str() function converts values to a string form so they can be combined with other strings.
It is a known fact that scanf() is faster than cin and getchar() is faster than scanf() in general.
You can simply use the fact that the function monad (->) r
already has an instance for MonadReader r
defined in Control.Monad.Reader
. You can write functions using just the MonadReader
constraint and use them either as normal functions or in other ReaderT
monads:
f :: MonadReader Int m => m Int
f = do
a <- ask
return $ 2 * a + 3 * a
normally :: Int
normally = f 1
-- normally == 5
readerly :: Reader Int Int
readerly = do
result <- f
return $ 2 * result
> runReader f 1
5
> runReader readerly 1
10
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With