Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any "standard" way to utilize the equivalence of Reader and a normal function?

Tags:

haskell

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?

like image 801
Bartek Banachewicz Avatar asked Feb 19 '15 18:02

Bartek Banachewicz


People also ask

What can be used instead of Scanf?

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.

Which library function can be used as an alternative to scan string value from user or keyboard?

To check for a string, we use hasNextLine(). Similarly, to check for a single character, we use hasNext().

What does str () do in Python?

The str() function converts values to a string form so they can be combined with other strings.

Is gets faster than Scanf?

It is a known fact that scanf() is faster than cin and getchar() is faster than scanf() in general.


1 Answers

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
like image 70
bheklilr Avatar answered Sep 21 '22 23:09

bheklilr