有什么 "standard" 方法可以利用 Reader 和普通函数的等价性吗?
Is there any "standard" way to utilize the equivalence of Reader and a normal function?
我正在编写一个框架,其中主要功能向用户询问类型 a -> [b]
的功能。
但是,由于该函数可能非常复杂,其实现通常如下所示:
fn a = extractPartOfAAndConvert a ++ extractAnotherPartofAAndConvert a
这就是为什么我认为使用 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
这又允许我做:
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
但是,我觉得我是在重新发明轮子。
有没有一种方法可以表达 Reader 的等价性,从而轻松编写此类泛型函数,而无需创建我自己的类型 class?
您可以简单地使用函数 monad (->) r
已经在 Control.Monad.Reader
中定义了 MonadReader r
的实例这一事实。您可以仅使用 MonadReader
约束来编写函数,并将它们用作普通函数或在其他 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
我正在编写一个框架,其中主要功能向用户询问类型 a -> [b]
的功能。
但是,由于该函数可能非常复杂,其实现通常如下所示:
fn a = extractPartOfAAndConvert a ++ extractAnotherPartofAAndConvert a
这就是为什么我认为使用 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
这又允许我做:
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
但是,我觉得我是在重新发明轮子。
有没有一种方法可以表达 Reader 的等价性,从而轻松编写此类泛型函数,而无需创建我自己的类型 class?
您可以简单地使用函数 monad (->) r
已经在 Control.Monad.Reader
中定义了 MonadReader r
的实例这一事实。您可以仅使用 MonadReader
约束来编写函数,并将它们用作普通函数或在其他 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