- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
TL;博士:
如何确保 randomRIO
生成的值的持久性(来自 System.Random
)在给定的 do
中陈述?
我如何在 IO Monad 中使用可变结构?
我最初的问题是(非常)错误 - 我正在更新标题,以便 future 想要了解在 IO monad 中使用可变结构的读者可以找到这篇文章。
加长版:
一抬头:
这看起来很长,但很多只是我概述了 exercism.io
作品。 (更新:最后两个代码块是我的代码的旧版本,作为引用包含在内,以防将来的读者希望根据评论/答案跟随代码中的迭代。)
练习概述:
我正在处理 Robot Name
来自(非常有指导意义的)exercism.io 的练习。练习包括创建一个 Robot
能够存储随机生成的名称的数据类型(下面包含练习 Readme
)。
对于那些不熟悉它的人,exercism.io
学习模型基于学生生成代码的自动化测试。每个练习由一系列测试(由测试作者编写)组成,解决方案代码必须能够通过所有这些测试。我们的代码必须通过给定练习的测试文件中的所有测试,然后才能进入下一个练习——一个有效的模型,imo。 ( Robot Name
是练习 #20 左右。)
在这个特定的练习中,我们被要求创建一个 Robot
数据类型和三个附带函数:mkRobot
, robotName
和 resetName
.
mkRobot
生成 Robot
的实例robotName
为未命名的 Robot
生成并“返回”一个唯一名称(即,robotName
不会覆盖预先存在的名称);如果 Robot
已经有一个名字,它只是“返回”现有的名字 resetName
用新名称覆盖先前存在的名称。 robotName
生成符合指定模式的名称(arobotName
分配的名称是持久的(例如,假设我们创建机器人 A 并使用 robotName
为他(或她)分配一个名字;第二次(在机器人 A 上)调用 robotName
不应覆盖他的名字)robotName
为不同的机器人生成唯一的名称(即,它测试我们实际上是在随机化过程)resetName
生成符合指定模式的名称(类似于测试 #0)resetName
分配的名称执着 resetName
分配一个不同的名称(即,resetName
给机器人一个与其当前名称不同的名称)resetName
一次仅影响一个机器人(即,假设我们有机器人 A 和机器人 B;重置机器人 A 的名称不应影响机器人 B 的名称)和 (ii) 由 resetName
生成的名称执着 {-# LANGUAGE NoMonomorphismRestriction #-}
module Robot (robotName, mkRobot, resetName) where
import Data.Map (fromList, findWithDefault)
import System.Random (Random, randomRIO)
import Control.Monad (replicateM)
import Data.IORef (IORef, newIORef, modifyIORef, readIORef)
newtype Robot = Robot { name :: String }
mkRobot :: IO (IORef Robot)
mkRobot = mkRobotName >>= return . Robot >>= newIORef
robotName :: IORef Robot -> IO String
robotName rr = readIORef rr >>= return . name
resetName :: IORef Robot -> IO ()
resetName rr = mkRobotName >>=
\newName -> modifyIORef rr (\r -> r {name = newName})
mkRobotName :: IO String
mkRobotName = replicateM 2 getRandLetter >>=
\l -> replicateM 3 getRandNumber >>=
\n -> return $ l ++ n
getRandNumber :: IO Char
getRandNumber = fmap getNumber $ randomRIO (1, 10)
getRandLetter :: IO Char
getRandLetter = fmap getLetter $ randomRIO (1, 26)
getNumber :: Int -> Char
getNumber i = findWithDefault ' ' i alphabet
where alphabet = fromList $ zip [1..] ['0'..'9']
getLetter :: Int -> Char
getLetter i = findWithDefault ' ' i alphabet
where alphabet = fromList $ zip [1..] ['A'..'Z']
mkRobotName
的评论功能,这有助于开始修复 mkRobot 功能。此版本的代码仅在测试 #5 上产生错误 - 测试 #5 与更改机器人的名称有关,这激发了对可变结构的需求......
{-# LANGUAGE NoMonomorphismRestriction #-}
module Robot (robotName, mkRobot, resetName) where
import Data.Map (fromList, findWithDefault)
import System.Random (Random, randomRIO)
import Control.Monad (replicateM)
data Robot = Robot (IO String)
resetName :: Robot -> IO String
resetName (Robot _) = mkRobotName >>= \name -> return name
mkRobot :: IO Robot
mkRobot = mkRobotName >>= \name -> return (Robot (return name))
robotName :: Robot -> IO String
robotName (Robot name) = name
-------------------------------------------------------------------------
--Supporting functions:
mkRobotName :: IO String
mkRobotName = replicateM 2 getRandLetter >>=
\l -> replicateM 3 getRandNumber >>=
\n -> return $ l ++ n
getRandNumber :: IO Char
getRandNumber = fmap getNumber $ randomRIO (1, 10)
getRandLetter :: IO Char
getRandLetter = fmap getLetter $ randomRIO (1, 26)
getNumber :: Int -> Char
getNumber i = findWithDefault ' ' i alphabet
where alphabet = fromList $ zip [1..] ['0'..'9']
getLetter :: Int -> Char
getLetter i = findWithDefault ' ' i alphabet
where alphabet = fromList $ zip [1..] ['A'..'Z']
{-# LANGUAGE NoMonomorphismRestriction #-}
module Robot (robotName, mkRobot, resetName) where
import Data.Map (fromList, findWithDefault)
import System.Random (Random, randomRIO)
data Robot = Robot (IO String)
resetName :: Robot -> IO Robot
resetName (Robot _) = return $ (Robot mkRobotName)
mkRobot :: IO Robot
mkRobot = return (Robot mkRobotName)
robotName :: Robot -> IO String
robotName (Robot name) = name
--the mass of code below is used to randomly generate names; it's probably
--possible to do it in way fewer lines. but the crux of the main problem lies
--with the three functions above
mkRobotName :: IO String
mkRobotName = getRandLetter >>=
\l1 -> getRandLetter >>=
\l2 -> getRandNumber >>=
\n1 -> getRandNumber >>=
\n2 -> getRandNumber >>=
\n3 -> return (l1:l2:n1:n2:n3:[])
getRandNumber :: IO Char
getRandNumber = randomRIO (1,10) >>= \i -> return $ getNumber i
getNumber :: Int -> Char
getNumber i = findWithDefault ' ' i alphabet
where alphabet = fromList $ zip [1..] ['0'..'9']
getRandLetter :: IO Char
getRandLetter = randomRIO (1,26) >>= \i -> return $ getLetter i
getLetter :: Int -> Char
getLetter i = findWithDefault ' ' i alphabet
where alphabet = fromList $ zip [1..] ['A'..'Z']
最佳答案
让我们根据测试的要求从类型开始。 mkRobot
返回 IO
中的内容
mkRobot :: IO r
robotName
获取从
mkRobot
返回的内容并返回
IO String
.
robotName :: r -> IO String
resetName
获取从
mkRobot
返回的内容并产生一个
IO
行动。从未使用过此操作的返回值,因此我们将使用单位类型
()
对于它这是正常的
IO
在 Hasekll 中没有结果的操作。
resetName :: r -> IO ()
r
需要能够表现得像它被
resetName
突变一样.对于在
IO
中表现得像可变的事物,我们有许多选择。 :
IORef
s,
STRef
s,
MVars
s 和软件事务内存。我对简单问题的首选是
IORef
.我将采取与您略有不同的策略,并将
IORef
分开。来自什么
Robot
是。
newtype Robot = Robot {name :: String}
Robot
一种非常纯的数据类型。那我就用
IORef Robot
为了什么
r
位于测试界面中。
IORef
s 提供了五个非常有用的函数来使用它们,我们将使用其中的三个。
newIORef :: a -> IO (IORef a)
做一个新的
IORef
持有提供的值。
readIORef :: IORef a -> IO a
读取存储在
IORef
中的值.
modifyIORef :: IORef a -> (a -> a) -> IO ()
将该函数应用于存储在
IORef
中的值.还有另外两个非常有用的函数我们不会使用,
writeIORef
它设置值而不查看那里的内容,和
atomicModifyIORef
它解决了编写多线程程序时大约一半的共享内存问题。我们将导入我们将使用的三个
import Data.IORef (IORef, newIORef, modifyIORef, readIORef)
Robot
我们将制作一个新的
IORef Robot
与
newIORef
.
mkRobot :: IO (IORef Robot)
mkRobot = mkRobotName >>= return . Robot >>= newIORef
Robot
与
readIORef
,然后
return
Robot
的
name
robotName :: IORef Robot -> IO String
robotName rr = readIORef rr >>= return . name
resetName
将变异
IORef
.我们将为机器人取一个新名称
mkRobotName
,然后拨打
modifyIORef
具有将机器人的名称设置为新名称的功能。
resetName :: IORef Robot -> IO ()
resetName rr = mkRobotName >>=
\newName -> modifyIORef rr (\r -> r {name = newName})
\r -> r {name = newName}
与
const (Robot newName)
相同,除了它只会改变
name
如果我们稍后决定向
Robot
添加一些其他字段数据类型。
关于haskell - 如何在 IO monad 中使用可变结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26809658/
为什么禁用类型像 type t = A of int | B of string * mutable int 虽然允许此类类型: type t = A of int | B of string * i
我正在寻找一种类似结构的数据结构,我可以从中创建多个实例并具有某种类型提示而不是不可变的。 所以我有这样的东西: class ConnectionConfig(NamedTuple): nam
我需要转到引用的结构: class SearchKnot { var isWord : Bool = false var text : String = "" var to
如sec 10.4.3中所述 当控制进入执行时,执行以下步骤 功能对象F(调用者)中包含的功能代码的上下文 提供thisArg,而调用方提供argumentsList: 如
i make a game that start display Activity indicator And activity indicator bottom display UiLable wi
编辑:我在这里不断获得支持。只是为了记录,我认为这不再重要。自从我发布它以来我就不再需要它了。 我想在 Scala 中执行以下操作... def save(srcPath: String, destP
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
如果您在Kotlin中访问List类型的Java值,则将获得(Mutable)List!类型。 例如。: Java代码: public class Example { public stati
我编写了 str 类(内置)的以下扩展,以便执行以下操作:假设我有字符串 "Ciao" ,通过做"Ciao" - "a"我想要的结果是字符串 "Cio" 。这是执行此操作的代码,并且运行良好: cla
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
我正在为我的公司设计一个数据库来管理商业贷款。每笔贷款都可以有担保人,可以是个人或公司,在借款业务失败时作为财务支持。 我有 3 个表:Loan、Person 和 Company,它们存储明显的信息。
我使用二进制序列化从 C# 类中保存 F# 记录。一切正常: F#: type GameState = { LevelStatus : LevelStatus
import javax.swing.JOptionPane; public class HW { public static void main(String[] args) { Strin
使用 flatbuffer mutable 有多少性能损失? 是否“正确”使用 FlatBuffers 来拥有一个应该可编辑的对象/结构(即游戏状态) 在我的示例中,我现在有以下类: class Ga
std::function create_function (args...) { int x = initial_value (args...); return [x] () mut
我需要在 for 循环中找到用户输入的字符。我通常会这样做 如果(句子[i] == 'e') 但是因为在这里,'e' 将是一个单字母字符变量,我不知道如何获取要比较的值。我不能只输入 if (sent
我有一个这样的算法: let seed: Foo = ... let mut stack: Vec = Vec::new(); stack.push(&seed); while let Some(ne
这个问题可能看起来非常基础,但我很难弄清楚如何做。我有一个整数,我需要使用 for 循环来循环整数次。 首先,我尝试了—— fn main() { let number = 10; // An
如果我有以下结构: struct MyStruct { tuple: (i32, i32) }; 以及以下函数: // This will not compile fn function(&mut s
我希望在每个 session 的基础上指定列的默认值。下面的脚本不起作用,但描述了我想如何使用它。我目前使用的是 MySQL 5.5.28,但如果需要可以升级。 CREATE TABLE my_tbl
我是一名优秀的程序员,十分优秀!