有没有任何“标准”利用Reader的等价性和正常功能的方法? [英] Is there any "standard" way to utilize the equivalence of Reader and a normal function?

查看:89
本文介绍了有没有任何“标准”利用Reader的等价性和正常功能的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个框架,其中主要功能向用户询问 a - >但是,由于该函数可能非常复杂,因此它的实现通常可能如下所示:

  fn a = extractPartOfAAndConvert a ++ extractAnotherPartofAAndConvert a 

这就是为什么我认为使用 Reader 可能是一个不错的,习惯性的想法。然而,与此同时,我意识到有些人可能不想使用monad。



在尝试时,我制作了这个解决方案:

  class Iso ab其中
isoFrom :: a - > b
isoTo :: b - > a

实例Iso aa其中
isoFrom = id
isoTo = id

实例Iso(a - > b)(Reader ab)其中
isoFrom f = reader f
isoTo m = runReader m

这反过来又允许我这样做:

  testCallback :: MyState  - >回拨 - > MyState 
testCallback myState cb = cb myState

- 重要签名
testCallbackGeneric :: Iso回调a => MyState - > a - > MyState
testCallbackGeneric cb =(isoTo cb)myState

callbackFunction :: Callback
callbackFunction s = s + 10

callbackMonad :: Reader MyState MyState
callbackMonad = do
x< - ask
return $ x - 10

-----------

让myStateA = testCallback myState callbackFunction
- 让myStateB = testCallback myState callbackMonad - 不起作用,显然
let myStateC = testCallbackGeneric myState callbackFunction
let myStateD = testCallbackGeneric myState callbackMonad

然而,我感觉非常像是在重新发明轮子。



有没有一种方法可以表达Reader的等价性,以便轻松编写这样的泛型函数,而不需要创建自己的类型类?

( - >)r 函数已经有一个<$ c $的实例C> MonadReader r 定义在 Control.Monad.Reader 中。您可以使用 MonadReader 约束来编写函数,并将它们作为普通函数或其他 ReaderT monad使用:

  f :: MonadReader Int m => m int 
f = do
a < - 请求
返回$ 2 * a + 3 * a

正常:: Int
正常= f 1
- 通常== 5

readerly :: Reader Int Int
readerly = do
结果< - f
返回$ 2 *结果

> runReader f 1
5
> runReader readerly 1
10


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?

解决方案

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

这篇关于有没有任何“标准”利用Reader的等价性和正常功能的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆