用于改变其周围环境的函数的 Haskell 表达式?

rwa*_*ace 5 haskell functional-programming

Haskell 是一种纯函数式语言,它为命令式表达式的等价物提供语法糖。例如,这个 Python 代码:

def f():
    n = 0
    for i in range(10):
        n += 1
    return n
Run Code Online (Sandbox Code Playgroud)

可以使用 monad 逐行翻译成同构的 Haskell 代码。

函数改变其周围环境的代码也是如此吗?例如:

def f():
    n = 0
    def g():
        nonlocal n
        n += 1
    for i in range(10):
        g()
    return n
Run Code Online (Sandbox Code Playgroud)

有没有办法将上面的一行一行翻译成同构的 Haskell?

我已经完全准备好接受答案是否定的,需要重新设计代码才能以不同的方式做同样的事情。但我认为值得询问是否有同构翻译。

Wil*_*sem 9

您可以使用 aState来封装State.

在这种情况下,您g可以看起来像:

import Control.Monad.State.Lazy(State, modify)

g :: State Int ()
g = modify (1+)
Run Code Online (Sandbox Code Playgroud)

thenf也是一个State首先将状态设置为0然后运行g十次的:

import Control.Monad(replicateM_)
import Control.Monad.State.Lazy(State, get, put)

f :: State Int Int
f = do
    put 0
    replicateM_ 10 g
    get
Run Code Online (Sandbox Code Playgroud)

然后你可以在我们提供初始状态的地方运行fevalState :: State s a -> s -> a它将返回项目的结果State s a,所以这里get返回的是什么:

Prelude Control.Monad.State.Lazy> evalState f 0
10
Run Code Online (Sandbox Code Playgroud)

  • 我准备使用`forM_ [1..10]`,因为它与Python稍微相似,因为`[1..10]`匹配`range(10)`,但`replicateM_ 10`无疑更优越。 (2认同)
  • 嗯,对于“状态”,范围的概念似乎并不那么容易翻译。只有一个变量“n”很简单,但是如果在该循环中增加两个不同的变量会怎么样?如何表示“g”对“n”的闭包?我认为这需要一个“STRef”或类似的东西。 (2认同)
  • @Bergi确实。我可以看到以下用于建模多个变量的选项:1) `State (Int, String, .....)` 以及正确组件的合适更新,2) 相同,但有记录,3) `STRef`s , 4) `IORef`。如果需要非本地返回(“break”、“raise Exception”、“longjmp”),则可能需要在顶部添加“ContT”。对于复杂的算法,`STRef` 似乎足够好了,除非需要 IO。 (2认同)