Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何使用Supply monad创建生成全局唯一名称的函数? 背景:_Haskell_Functional Programming_Unique_Monads_State Monad - Fatal编程技术网

Haskell 如何使用Supply monad创建生成全局唯一名称的函数? 背景:

Haskell 如何使用Supply monad创建生成全局唯一名称的函数? 背景:,haskell,functional-programming,unique,monads,state-monad,Haskell,Functional Programming,Unique,Monads,State Monad,我正在做一个代码翻译项目,需要我生成变量名。我生成的所有名称都不应相互重复 我真的很沮丧,因为如果使用Python生成器函数,这将非常简单和优雅 我所尝试的: 我以前的做法是通过递归调用将计数器变量向下传递给我的翻译代码,并在基本上每个函数的返回值中向上传递(可能是递增的)计数器 这真是一团糟:它添加了一个额外的参数来跟踪这些函数中的每一个;更糟糕的是,它迫使我处理混乱的元组返回值,否则我会得到一个简单的一元返回值 在我与Haskell相处的短短时间里,我从未真正精通过monad,但我有一个想法

我正在做一个代码翻译项目,需要我生成变量名。我生成的所有名称都不应相互重复

我真的很沮丧,因为如果使用Python生成器函数,这将非常简单和优雅

我所尝试的: 我以前的做法是通过递归调用将计数器变量向下传递给我的翻译代码,并在基本上每个函数的返回值中向上传递(可能是递增的)计数器

这真是一团糟:它添加了一个额外的参数来跟踪这些函数中的每一个;更糟糕的是,它迫使我处理混乱的元组返回值,否则我会得到一个简单的一元返回值

在我与Haskell相处的短短时间里,我从未真正精通过monad,但我有一个想法,我可以在
状态
monad上使用包装器来模拟全局计数器变量。三天来,我一直在尝试摸索单子并制作自己的单子,然后尝试修改其他人的单子以生成我所需的值,最后我决定直接使用其他人的高级单子(可能需要一些修改)

我现在的问题是: 我已经将和模块确定为一对,它们可能提供我需要的简单类型的接口。不幸的是,我不知道如何使用它们

尤其是
MonadSupply
模块文档提供了这个很好的示例用例:

runSupplyVars x = runSupply x vars
    where vars = [replicate k ['a'..'z'] | k <- [1..]] >>= sequence
我曾尝试将大量(小时价值)不同的内容传递给此函数,但没有成功。我还尝试将该函数传递给其他一些函数,看看它们是否会隐式地提供我需要的参数。到目前为止运气不好

问题是: 是否有人可以提供此
runSupplyVars
函数的示例用例


有可能用它来做我想做的事吗?我希望有一个可以从程序中的任何地方调用的函数,在每次调用时为我提供不同的变量名或整数。

要实际使用
Supply
monad,您应该使用它来构造代码,并在实际需要名称时调用
Supply
函数

例如,这将产生一个新的变量名,前缀为
var\uu
,只是为了说明如何从供应中获取并使用它:

newVar :: Supply [Char] [Char]
newVar = do
    name <- supply
    return ("var"_++name)
下面是一个更完整的示例,将所有内容放在一起。请注意使用
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
导入MonadSupply
导入控制.Monad.Identity
main::IO()
main=do
let result=runSupplyVars realProgram
打印结果
realProgram::Supply[Char]Int
realProgram=do
x=序列

我想我最大的问题是
do
符号。如果我从
do
块的第一行调用
runSupplyVars
,比如
pb0
(根据我的编译错误消息)。我假设这意味着,无论我使用什么顶级函数来启动我的翻译(比如
foo
)都需要该返回类型,然后我可以在
foo
中自由调用
newVar
,以及我在
foo
中调用的任何函数。我可以返回一些这种类型的垃圾吗?好的,我看到了你的部分问题-作为外部世界入口点的
main
函数的
do
符号正在处理
IO
monad,而对于你的其余代码,它将处理
Supply
monad。我已经添加了一个例子。顺便说一句,如果您还想在代码的其余部分使用
IO
,那么您要么需要一个“monad transformer”(
SupplyT
,在wiki页面上),要么使用
IORef
来传递名称supply。这又增加了一层需要理解的地方,所以最好先掌握这种风格。我想你可能误读了,这是t0而不是IO。我没有做任何IO或使用monad(除非你说我需要?),我将仔细查看你的新示例代码。顺便说一句,如果我弄明白了这一点,你已经获得了丰厚的赏金。我没有误读
t0
-我猜你正在使用
IO
,因为你说从“我的
do
的第一行”内部调用
runSupplyVars
,从中我推断它可能来自
IO
monad中的
main
Supply
monad的工作方式是建立一个类型为
Supply[Char]a
的大型操作,然后使用
runSupplyVars
在“纯”代码中消除它。因此,无论从何处调用它,调用看起来都更像
let result=runSupplyVars realProgram
,而不是
do p
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
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