【问题标题】:Natural number sequence generator自然数序列生成器
【发布时间】:2010-10-20 20:25:55
【问题描述】:

据我所知,Haskell 没有全局状态,所以有没有办法编写一个函数 f 来返回 f(n - 1) + 1,其中 n 是函数调用的数量, f(1) = 0.

它不应该接受任何参数并且像func f一样使用

Prelude> f () 
0
Prelude> f ()
1

【问题讨论】:

  • 如果n 是函数调用的编号(我假设您的意思是该函数之前被调用的频率?)那么函数的参数是什么?如果值应该依赖于n 而不是参数,那么f 1 = 0 怎么可能?
  • 我的意思是当你第一次调用函数时它返回0
  • @sepp2k 对,应该返回调用的号码
  • 我不确定答案,但这会使您的方法不纯或有副作用
  • 我想重申这是一个非常un-Haskelly 设计问题。您应该使用状态单子。

标签: haskell state monads


【解决方案1】:

如果不使用unsafePerform 之类的技巧,就不可能定义一个可以像您在示例中显示的那样调用的函数。但是,可以定义一个 IO 操作来执行您想要的操作,并且可以像这样使用:

Prelude> x <- f 
Prelude> x
0
Prelude> x <- f
Prelude> x
1

这是一个使用 IORefs 做你想做的事的示例程序:

import Data.IORef

main = do counter <- newIORef 0
          let f = do count <- readIORef counter
                     modifyIORef counter (+ 1)
                     return count          
          x <- f
          print x
          x <- f
          print x

【讨论】:

  • 这样的IO动作怎么写?
  • 一个小插曲:使用unsafePerformIO 可以定义一个看起来可以做你想做的事情的纯函数,但不要尝试。它几乎肯定不会正常工作。
【解决方案2】:

您要求在每次调用过程时更新某些(可能是隐藏的)状态,以便函数在给定相同输入的情况下返回不同的结果。

显然,这不是一个引用透明的函数,所以我们必须在 Haskell 的纯默认模式中添加一些东西。我们通过单子添加计算概念。你只需要选择你需要的一元环境。

状态单子

最精确的方法是通过 State monad(不要与“ST”monad 混淆)将状态的概念添加到您的程序中:

import Control.Monad.State.Strict 

-- a (stateful) procedure, that returns and increments an internal state counter 
f :: State Int Int 
f = do 
    n <- get 
    put (n+1) 
    return n 

-- Call 'f' a bunch of times, print the final state. 
main = print $ execState code 0 
 where 
    code = do f; f; f; f

现在 'f' 有一个内部状态组件。

类似地,IO 等更丰富的环境允许使用状态,因此您可以使用 IO monad(或其他一些包含状态的计算环境)。

【讨论】:

    【解决方案3】:

    如果您更喜欢可以从 ghci 命令行键入的内容,那么:

    Prelude> :m + Data.IORef
    Prelude Data.IORef> n <- newIORef 0
    Prelude Data.IORef> let f = do { v <- readIORef n ; writeIORef n (v+1); return v}
    Prelude Data.IORef> f
    0
    Prelude Data.IORef> f
    1
    Prelude Data.IORef> f
    2
    Prelude Data.IORef> f
    3
    

    您的示例想调用“f ()”,但这是 Haskell 没有的 C-ism。如果您真的想要,那么只需更改“f”的定义即可开始

    let f _ = do {...
    

    “()”在Haskell中被定义为单位值,这是单位类型“()”的唯一值。你可以用你想要的任何参数调用“f”;它将被忽略。

    【讨论】:

      【解决方案4】:

      试试这样的:

      f 1 = 0
      f n = f (n-1) + 1
      

      编辑:看来我误解了你的问题; ,你不能在 haskell 中做这样的事情;函数应该是pure。您示例中的函数不是纯函数

      【讨论】:

      • 错字:你有f (n-1) - 1,他们想要f (n-1) + 1
      • @Antal S-Z 你很快!我刚发完就看到了,不过你好像也看到了:)
      猜你喜欢
      • 2014-12-04
      • 2015-07-14
      • 1970-01-01
      • 2019-09-05
      • 1970-01-01
      • 2022-11-05
      • 2011-05-28
      • 1970-01-01
      • 2011-03-21
      相关资源
      最近更新 更多