readerT的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE FlexibleContexts #-}

module Lib
( someFunc
) where

import Control.Monad (liftM, ap)

-- Step 1: 定义 ReaderT 类型
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }

-- Step 2: 实现 Functor 实例
instance Functor m => Functor (ReaderT r m) where
fmap f (ReaderT r) = ReaderT $ \env -> fmap f (r env)

-- Step 3: 实现 Applicative 实例
instance Monad m => Applicative (ReaderT r m) where
pure x = ReaderT $ \_ -> pure x
(ReaderT f) <*> (ReaderT x) = ReaderT $ \env -> do
func <- f env
val <- x env
return (func val)

-- Step 4: 实现 Monad 实例
instance Monad m => Monad (ReaderT r m) where
return x = ReaderT $ \_ -> return x
(ReaderT r) >>= k = ReaderT $ \env -> do
a <- r env
let ReaderT r' = k a
r' env

-- Step 5: 实现 MonadReader 类
class Monad m => MonadReader r m | m -> r where
ask :: m r
local :: (r -> r) -> m a -> m a

-- Step 6: 实现 ReaderT 的 MonadReader 实例
instance Monad m => MonadReader r (ReaderT r m) where
ask = ReaderT return
local f (ReaderT r) = ReaderT $ \env -> r (f env)

-- Step 7: 定义 someFunc 测试函数
testReaderT :: IO ()
testReaderT = do
let reader = ReaderT $ \env -> return ("Environment: " ++ env)
result <- runReaderT reader "TestEnv"
putStrLn result

let askReader = ask :: ReaderT String IO String
env <- runReaderT askReader "TestEnv"
putStrLn ("ask: " ++ env)

let localReader = local (\env -> env ++ " Modified") askReader
modifiedEnv <- runReaderT localReader "TestEnv"
putStrLn ("local: " ++ modifiedEnv)

-- 修改后的 testMonadReader 函数,启用 FlexibleContexts
testMonadReader :: (MonadReader String m) => m String
testMonadReader = do
env <- ask -- 获取环境变量,这里 r 被具体化为 String
let modifiedEnv = env ++ " Modified"
return modifiedEnv

someFunc :: IO ()
someFunc = do
-- 运行 ReaderT 测试
testReaderT

-- 运行使用 MonadReader 约束的测试
let result = testMonadReader :: ReaderT String IO String
modifiedEnv <- runReaderT result "TestEnv"
putStrLn ("testMonadReader: " ++ modifiedEnv)

对于一个需要环境变量r的函数,既可以使用MonadReader约束从而运行在不同的上下文中,也可以使用ReaderT作为签名。

本质

ReaderT的本质就是一个r -> m a的函数,m a也是一个函数,通过闭包的方式访问r。

lift

1
2
3
4
5
class MonadTrans t where
lift :: Monad m => m a -> t m a

instance MonadTrans (ReaderT r) where
lift ma = ReaderT $ \_ -> ma