首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用get从Haskell中的State Monad解压和打印值

使用get从Haskell中的State Monad解压和打印值
EN

Stack Overflow用户
提问于 2022-11-22 11:07:37
回答 2查看 87关注 0票数 1

我试图很好地掌握状态Monad (以及一般的Monad),但是我很难用状态Monad和do-表示法重写下面的函数,这是我提出here的一个练习。

代码语言:javascript
复制
import Control.Monad
import System.Random
import Data.Complex
import qualified System.Random as R
import Control.Monad.Trans.State.Lazy

giveRandomElement :: [a] -> State R.StdGen a
giveRandomElement lst = do
  let n = length lst
  rand <- state $ randomR (0, n-1)
  return $ lst !! rand

random_response_monad :: a -> [a] -> State R.StdGen a
random_response_monad true_answer answers = do      
        tal <- state $ randomR (0, 1) :: StateT StdGen Data.Functor.Identity.Identity a     
        if (tal == 0) then true_answer
        else giveRandomElement answers

显而易见,tal-variable存在一些类型问题,因为它发生在if-clause和do-expression的第一行中。正如从代码中可以看到的那样,我试图通过特定类型强制后者,以便使它对我自己来说也是明确和清晰的。我这样做是通过编译器--当我第一次尝试强制它成为Int-type时,我得到了这样的建议。但是,我无法在if-语句中使用该值,我也不知道如何转换或解压缩该值,以便将其作为Int。到目前为止,我已经尝试在tal <- ...resp <- get $ tal之后添加折叠行,但是我得到了这个输出。

代码语言:javascript
复制
error:
    * Couldn't match expected type: t0
                                    -> StateT StdGen Data.Functor.Identity.Identity a1
                  with actual type: StateT s0 m0 s0
    * The first argument of ($) takes one value argument,
        but its type `StateT s0 m0 s0' has none
      In a stmt of a 'do' block: resp <- get $ tal
      In the expression:
        do tal <- state $ randomR (0, 1)
           resp <- get $ tal
           if (resp == 0) then
               giveRandomElement answers
           else
               giveRandomElement answers
    * Relevant bindings include tal :: t0 

此外,我感到困惑的是,什么是“打印”giveRandomElement返回的结果的最佳方法,因为该类型基于为State-monad声明的类型,据我所知,该类型也不使用deriving Show。但是,这也许可以通过解压上面询问的值来解决。

编辑

我使用了上面的包,尽管它们可能并不都在上面的代码中使用。我不确定代码使用的是哪种代码,我怀疑qualified System.Random as R

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-11-22 13:47:30

以下代码行:

代码语言:javascript
复制
        tal <- state $ randomR (0, 1) :: StateT StdGen Data.Functor.Identity.Identity a    

是相当长的,可能会导致水平滑块出现,至少在我的平台上。

因此,很容易忽略的是,在它的末尾使用a类型变量,而它应该是Int

此外,if结构的两个分支使用不同的类型,从而使构造类型错误。then分支提供一个纯a值,而else分支提供一个一元值。这很容易通过更改为:

代码语言:javascript
复制
   if (tal == 0)  then  return true_answer

由于return库函数(稍微命名不当)将其参数封装到手头的monad中。

下面的代码试图保持代码行的足够短,似乎工作得很好:

代码语言:javascript
复制
import            Control.Monad.State
import qualified  System.Random          as  R
import qualified  Data.Functor.Identity  as  DFI

giveRandomElement :: [a] -> State R.StdGen a
giveRandomElement lst = do
    let n = length lst
    rand <- state $ R.randomR (0, n-1)
    return $ lst !! rand


type ActionType = StateT R.StdGen DFI.Identity Int

random_response_monad :: a -> [a] -> State R.StdGen a
random_response_monad true_answer answers = do        
        tal <- (state $ R.randomR (0, 1) :: ActionType)
        if (tal == 0)  then  return true_answer
                       else  giveRandomElement answers


main :: IO ()
main = do
    let  g0       =  R.mkStdGen 4243
         action   =  random_response_monad 20 [0..9]
         (k, g1)  =  runState action g0
    putStrLn $ "k is set to: " ++ (show k)

附带注意:代码也可以在没有复杂类型注释的情况下编译,如下所示:

代码语言:javascript
复制
       tal <- state $ R.randomR (0::Int, 1)
票数 1
EN

Stack Overflow用户

发布于 2022-11-30 21:17:46

像这样的事情似乎很有效:

代码语言:javascript
复制
random_response_monad :: a -> [a] -> State R.StdGen a
random_response_monad true_answer answers = do      
  tal <- state $ randomR (0 :: Int, 1)
  if (tal == 0) then return true_answer
  else giveRandomElement answers

两个变化:

  • 使用类型注释告诉编译器01是什么意思。一旦您告诉编译器0是哪种类型,那么1具有相同的类型。(请记住,在Haskell中,数字是多态的。如果没有更多的信息,Haskell将在true_answer.

前面看到像0这样的文字可能是任何Num Num

以下是来自GHCi的几个示例,它们似乎表明了它的工作原理:

代码语言:javascript
复制
ghci> evalState (random_response_monad 42 [0..9]) <$> newStdGen
4
ghci> evalState (random_response_monad 42 [0..9]) <$> newStdGen
1
ghci> evalState (random_response_monad 42 [0..9]) <$> newStdGen
42
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74531622

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档