mac*_*ing 4 monads haskell functional-programming unique state-monad
我正在做一个代码翻译项目,需要我生成变量名.我生成的名称都不应该是彼此重复的.
我真的很沮丧,因为这将是一个愚蠢的简单和优雅的Python生成器功能.
我之前做的方式是通过递归调用我的翻译代码传递一个计数器变量,并将(可能递增的)计数器传递回基本上每个函数的返回值.
这真的很乱:它增加了一个额外的参数来跟踪这些功能; 更糟糕的是它仍然迫使我使用凌乱的元组返回值,否则我将有一个简单的一元返回值.
在Haskell的短暂时间里,我从来没有真正熟练使用monad,但我有一个想法,我可以使用Statemonad 上的包装来模拟全局计数器变量.在试图修改monad并制作我自己的monad三天之后,然后试图改变别人的monad来生成我需要的值,我终于使用其他人的高级monad来自我辞职了(也许有一些改动.)
我已经将MonadSupply和MonadUnique模块确定为一对可能提供我需要的简单接口的一对.不幸的是我无法弄清楚如何使用它们.
特别是MonadSupply模块文档提供了这个很好的示例用例:
runSupplyVars x = runSupply x vars
where vars = [replicate k ['a'..'z'] | k <- [1..]] >>= sequence
Run Code Online (Sandbox Code Playgroud)
看起来像我想要的!一旦我得到了编译模块,我在解释器中检查了这个函数的类型:
> :t runSupplyVars
runSupplyVars :: Supply [Char] a -> Identity (a, [[Char]])
Run Code Online (Sandbox Code Playgroud)
我已经尝试将很多(数小时)不同的东西传递给这个功能,但没有成功.我也尝试将函数传递给其他各种函数,以查看它们是否会隐式提供我需要的参数.到目前为止没有运气.
有人可以提供此runSupplyVars功能的示例用例吗?
是否有可能做我正在考虑的事情?我希望有一个我可以在程序中的任何地方调用的函数,它将在每次调用时为我提供不同的变量名或整数.
要实际使用Supplymonad,您应该使用do符号构造代码,并supply在实际需要名称时调用该函数.
例如,这将生成一个前缀为的新变量名var_,只是为了说明如何从供应中获取并使用它:
newVar :: Supply [Char] [Char]
newVar = do
name <- supply
return ("var"_++name)
Run Code Online (Sandbox Code Playgroud)
您需要围绕Supplymonad 构建整个程序,然后只runSupplyVars在顶层调用一次,否则程序的不同部分将具有独立的供应,因此可能会重用相同的变量名称.
最后,你需要runIdentity从Control.Monad.Identity到的结果解压runSupplyVars到类型的基本元组(a, [[Char]]),然后扔掉第二个值这仅仅是未使用名称的(无限)列表.你可能最好重新定义runSupplyVars为你做这件事:
import Control.Monad.Identity
[...]
runSupplyVars :: Supply [Char] a -> a
runSupplyVars x = fst (runIdentity (runSupply x vars))
where vars = [replicate k ['a'..'z'] | k <- [1..]] >>= sequence
Run Code Online (Sandbox Code Playgroud)
这是一个更完整的例子,将它们放在一起.注意与不同的单子do符号使用- IO对于main功能,并Supply [Char]为realProgram可能是最在一个更大的版本的代码的其余部分:
import MonadSupply
import Control.Monad.Identity
main :: IO ()
main = do
let result = runSupplyVars realProgram
print result
realProgram :: Supply [Char] Int
realProgram = do
x <- newVar
return 0
newVar :: Supply [Char] [Char]
newVar = do
name <- supply
return ("var_"++name)
runSupplyVars :: Supply [Char] a -> a
runSupplyVars x = fst (runIdentity (runSupply x vars))
where vars = [replicate k ['a'..'z'] | k <- [1..]] >>= sequence
Run Code Online (Sandbox Code Playgroud)