Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.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 使用状态单子将我的所有函数转换为单子函数_Haskell_Monads_State Monad - Fatal编程技术网

Haskell 使用状态单子将我的所有函数转换为单子函数

Haskell 使用状态单子将我的所有函数转换为单子函数,haskell,monads,state-monad,Haskell,Monads,State Monad,我在Haskell写了一个加密库来学习密码学和Monad。(不适用于实际使用!)我的素性测试函数类型为 prime :: (Integral a, Random a, RandomGen g) => a -> State g Bool 如你所见,我使用状态单子,所以我没有线程一直通过生成器。在内部,素数函数使用Miller-Rabin测试,它依赖于随机数,这就是素数函数也必须依赖于随机数的原因。这在某种程度上是有意义的,因为素函数只做概率测试 下面是整个素数函数,仅供参考,但我认为

我在Haskell写了一个加密库来学习密码学和Monad。(不适用于实际使用!)我的素性测试函数类型为

prime :: (Integral a, Random a, RandomGen g) => a -> State g Bool
如你所见,我使用状态单子,所以我没有线程一直通过生成器。在内部,素数函数使用Miller-Rabin测试,它依赖于随机数,这就是素数函数也必须依赖于随机数的原因。这在某种程度上是有意义的,因为素函数只做概率测试

下面是整个素数函数,仅供参考,但我认为您无需阅读

当时我使用了一个简单的、确定性的素性测试函数。我还没有重写
recover
函数,但我已经知道
beta
函数依赖于素数,因此它和
recover
也将依赖素数。两者都必须从简单的非一元函数转变为两个一元函数,尽管它们使用状态单元/随机性的原因很深

我忍不住认为所有的代码都变得更加复杂,因为它必须是一元的。在哈斯凯尔这样的情况下,我是错过了什么,还是总是这样

我能想到的一个解决办法是

prime' n = runState (prime n) (mkStdGen 123)
并使用
prime'
。这个解决方案提出了两个问题

  • 这是个坏主意吗?我觉得它不太优雅
  • 从一元代码到非一元代码的“切割”应该在哪里?因为我还有这样的函数
    genPrime
  • _

    genPrime::(RandomGen g,Random a,Integral a)=>a->状态g a
    genPrime b=do
    
    n这确实是对单子的有效批评,因为它们是在Haskell中实现的。短期内,我看不到比您提到的更好的解决方案,而将所有代码切换为一元风格可能是最健壮的一种,尽管它们比自然风格更为重要,事实上,移植一个大型代码库可能是一件痛苦的事,尽管如果您想添加更多的外部效果,以后可能会有回报

    我认为代数效应可以优雅地解决这个问题,例如:

    • ()

    所有函数都用其效果注释
    a->eff b
    ,然而,与Haskell相反,它们都可以像纯函数
    a->b
    (因此是有效函数的特例,效果签名为空)一样简单地组合。然后,该语言确保效果形成半格,以便可以组合具有不同效果的函数

    在哈斯凯尔似乎很难有这样一个系统。Free(r)monads库允许以类似的方式组合效果类型,但仍然需要术语级别的显式monadic样式。 一个有趣的想法是重载函数应用程序,这样就可以隐式地将其更改为
    (>>=)
    ,但我找不到这样做的原则性方法。主要问题是,函数
    a->mb
    既被视为对
    m
    和辅酶域
    b
    有影响的有效函数,也被视为对辅酶域
    mb
    有影响的纯函数。我们如何推断何时使用
    ($)
    (>=)


    在随机性的特殊情况下,我曾经有过一个与可拆分随机生成器(无耻插头)相关的想法:

    一切都是正确的。你似乎唯一误解的是一元代码并不一定比非一元代码复杂。它只是有点不同,需要一点时间来适应。那么,即使使用概率素数检查器,
    recover
    是否仍然具有确定性?如果它只是渐近确定的(即蒙特卡罗),那么用
    MonadRandom=>…
    签名来明确它似乎是合适的。
    recover :: Integral a => [a] -> [a] -> a -> a
    recover pi_s si_s q = sum prods `mod` q
      where
        bi_s  = map (beta pi_s q) pi_s
        prods = zipWith (*) bi_s si_s
    
    prime' n = runState (prime n) (mkStdGen 123)
    
    genPrime :: (RandomGen g, Random a, Integral a) => a -> State g a
    genPrime b = do
      n  <- randomR_st (2^(b-1),2^b-1)
      ps <- filterM prime [n..]
      return $ head ps