是否有任何"标准"方式来利用Reader和正常函数的等价?

Bar*_*icz 7 haskell

我正在编写一个框架,其中main函数询问用户类型的功能a -> [b].

但是,因为该函数可能非常复杂,所以它的实现通常如下所示:

fn a = extractPartOfAAndConvert a ++ extractAnotherPartofAAndConvert a
Run Code Online (Sandbox Code Playgroud)

这就是为什么我认为使用Reader可能是一个很好的,惯用的想法来对抗它.然而,与此同时,我意识到有些人可能不想使用monad.

在试验的过程中,我精心设计了这个解决方案:

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
Run Code Online (Sandbox Code Playgroud)

这反过来允许我这样做:

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
Run Code Online (Sandbox Code Playgroud)

但是,我觉得我非常喜欢重新发明轮子.

有没有办法表达Reader的等价性,轻松编写这样的泛型函数,而无需创建自己的类型类?

bhe*_*ilr 10

您可以简单地使用函数monad (->) r已经具有MonadReader r定义的实例的事实Control.Monad.Reader.您可以仅使用MonadReader约束编写函数,并将它们用作普通函数或其他ReaderTmonad:

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
Run Code Online (Sandbox Code Playgroud)