追加单子
Appending monad
只要putChar
我就可以做这样的事情:
f =
do
putChar 'a'
putChar 'b'
g
putChar 'f'
putChar 'g'
g =
do
putChar 'c'
putChar 'd'
putChar 'e'
当我"run"这个(通过说main = f
)时我会发现什么,它只会按顺序打印出字符。
我要找的是非IO
版本。有点像这样的东西:
f =
do
append 'a'
append 'b'
g
append 'f'
append 'g'
g =
do
append 'c'
append 'd'
append 'e'
还有一个函数,比如 runAppend :: t a -> [a]
这样 runAppend f
= ['a','b','c','d','e','f','g']
自然地,我希望它在线性时间内达到 运行(即不会遇到像 ++
这样的问题,当你以错误的顺序进行连接时)。
这似乎是一个相当常见的用例,所以我猜它是存在的,如果有人能指点我就好了,我不想重新发明轮子。
Writer monad 这样做:
> let g = tell "b" >> tell "c" >> tell "d"
> runWriter (tell "a" >> g >> tell "e")
((),"abcde")
您可以为此使用 Writer
monad:
import Control.Monad.Writer
import Data.DList (DList)
import qualified Data.DList as DList
type Append c = Writer (DList c)
append :: c -> Append c ()
append = tell . pure
runAppend :: Append c () -> [c]
runAppend = DList.toList . execWriter
f, g :: Append Char ()
这比必要的要复杂一些,因为它使用 DList Char
而不是 String
。 DList
为您提供了一个高效的 Monoid
实例,适用于您不断追加到末尾的情况。
只要putChar
我就可以做这样的事情:
f =
do
putChar 'a'
putChar 'b'
g
putChar 'f'
putChar 'g'
g =
do
putChar 'c'
putChar 'd'
putChar 'e'
当我"run"这个(通过说main = f
)时我会发现什么,它只会按顺序打印出字符。
我要找的是非IO
版本。有点像这样的东西:
f =
do
append 'a'
append 'b'
g
append 'f'
append 'g'
g =
do
append 'c'
append 'd'
append 'e'
还有一个函数,比如 runAppend :: t a -> [a]
这样 runAppend f
= ['a','b','c','d','e','f','g']
自然地,我希望它在线性时间内达到 运行(即不会遇到像 ++
这样的问题,当你以错误的顺序进行连接时)。
这似乎是一个相当常见的用例,所以我猜它是存在的,如果有人能指点我就好了,我不想重新发明轮子。
Writer monad 这样做:
> let g = tell "b" >> tell "c" >> tell "d"
> runWriter (tell "a" >> g >> tell "e")
((),"abcde")
您可以为此使用 Writer
monad:
import Control.Monad.Writer
import Data.DList (DList)
import qualified Data.DList as DList
type Append c = Writer (DList c)
append :: c -> Append c ()
append = tell . pure
runAppend :: Append c () -> [c]
runAppend = DList.toList . execWriter
f, g :: Append Char ()
这比必要的要复杂一些,因为它使用 DList Char
而不是 String
。 DList
为您提供了一个高效的 Monoid
实例,适用于您不断追加到末尾的情况。