将随机数列表写入文件。没有实例(显示(IO a0))
Write list of random numbers to file. No Instance for (Show (IO a0))
我正在尝试将文件中的随机整数列表写入文件。这里writeFile
好像有问题。当我使用函数 randomFile
时,它显示 no instance for (Show (IO a0))
。我看到 writeFile
没有在屏幕上打印任何东西,但是 IO()
,所以当我调用函数 randomFile 1 2 3
时它说 no Instance for Show (IO a0)
但实际上我只想执行函数而不是必须打印任何东西,但我怎样才能避免这个问题。我可能在这里犯了很多错误。任何帮助。
import Control.Monad
import Control.Applicative
import System.Random
randNo mind maxd = randomRIO (mind,maxd)
randomFile mind maxd noe = do
let l=(replicate (fromInteger(noe ^ noe)) ( mind `randNo` maxd))
writeFile "RFile.txt" (show l)
我觉得你对IO是什么有误解。如果您还没有这样做,我强烈建议您通过 Input and Output section of Learn You a Haskell.
IO
与 print
没有任何关系。在 Haskell 中,由您自己的代码创建的每个内存条目都被视为 "pure",而触及计算机其余部分的任何条目都存在于 IO 中(除了一些例外,您将随着时间的推移了解)。
我们使用称为 Monad 的东西对 IO 进行建模。你做的时间越长,你就会了解得越多 Haskell。为了理解这一点,让我们看一些使用和不使用 IO 的代码示例:
noIOused :: Int -> Int
noIOused x = x + 5
usesIO :: Int -> IO Int
usesIO x = print x >> return (x + 5)
usesIO2 :: Int -> IO Int
usesIO2 x = do
print x
return (x + 5)
第一个函数是"pure"。第二个和第三个函数有一个 IO "effect",以打印到屏幕的形式出现。 usesIO
和 usesIO2
只是做同一件事的两种不同方式(它是相同的代码,但语法不同)。我将使用第二种格式,从这里称为 do
表示法。
以下是您可能产生 IO 效果的其他一些方式:
add5WithFile :: Int -> IO Int
add5WithFile x = do
writeFile "someFile.txt" (show x)
return (x + 5)
注意在那个函数中我们没有打印任何东西,我们写了一个文件。但是写入文件有一个副作用,并且会与系统的其余部分交互。所以我们 return 的任何值都必须包含在 IO 中。
addRandom :: Int -> IO Int
addRandom x = do
y <- randomRIO (1,10)
return (x + y)
在addRandom
中我们调用了randomRIO (1,10)
。但问题是 randomRIO 没有 return 和 Int
。它 return 是一个 IO Int
。为什么?因为为了获得真正的随机性,我们需要以某种方式与系统进行交互。为了解决这个问题,我们必须暂时去除 IO。这就是这一行的来源:
y <- randomRIO (1,10)
那个 <-
箭头告诉我们我们想要一个 y
值在 IO 之外。只要我们保持在 do
语法内,y
值就会成为 "pure"。现在我们可以像使用任何其他值一样使用它了。
例如,我们不能这样做:
let w = x + (randomRIO (1,10))
因为那会尝试将 Int
添加到 IO Int
。不幸的是,我们的 +
函数不知道该怎么做。所以首先我们必须将 randomRIO
的结果 "bind" 到 y
,然后才能将其添加到 x
.
现在让我们看看您的代码:
let l=(replicate (fromInteger(noe ^ noe)) ( mind `randNo` maxd))
writeFile "RFile.txt" (show l)
l
的类型实际上是IO a0
。它是 a0
因为你还没有告诉编译器你想要什么样的数字。所以它不知道你想要的是小数、双精度数、大整数还是其他什么。
所以第一个问题就是让编译器多了解一点你想要什么样的随机数。我们通过添加类型注释来做到这一点:
randNo :: Int -> Int -> IO Int
randNo mind maxd = randomRIO (mind,maxd)
现在你和编译器都知道 randNo
是什么类型的值了。
现在我们需要 "bind" do
符号内的那个值来暂时转义 IO。你可能认为这很简单,像这样:
randomFile mind maxd noe = do
l <- replicate (fromInteger(noe ^ noe)) ( mind `randNo` maxd)
writeFile "RFile.txt" (show l)
肯定会 "bind" IO Int
到 l
对吗?不幸的是没有。这里的问题是 replicate
是 Int -> a -> [a]
形式的函数。也就是说,给定一个数字和一个类型,它会给你一个该类型的列表。
如果你给 replicate
一个 IO Int
,它就会变成 [IO Int]
。这实际上看起来更像这样: List (IO Int)
除了我们使用 []
作为列表的语法糖。不幸的是,如果我们想 "bind" 一个 IO
值到 <-
的东西,它必须是最外面的类型。
所以你需要的是一种将 [IO Int]
变成 IO [Int]
的方法。有两种方法可以做到这一点。如果我们 put \[IO a\] -> IO \[a\]
into Hoogle 我们得到这个:
sequence :: Monad m => [m a] -> m [a]
正如我之前提到的,我们将 IO 概括为称为 Monad 的东西。这没什么大不了的,我们可以假装 sequence
有这个签名:sequence :: [IO a] -> IO [a]
并且它只是专门用于 IO 的东西。
现在你的函数将像这样完成:
randomFile mind maxd noe = do
l <- sequence (replicate (fromInteger(noe ^ noe)) ( mind `randNo` maxd))
writeFile "RFile.txt" (show l)
但是 sequence
后跟 replicate
是人们必须一直做的事情。所以有人去做了一个叫做 replicateM
:
的函数
replicateM :: Monad m => Int -> m a -> m [a]
现在我们可以这样写你的函数了:
randomFile mind maxd noe = do
l <- replicateM (fromInteger(noe ^ noe)) ( mind `randNo` maxd)
writeFile "RFile.txt" (show l)
对于一些真正的 Haskell 魔术,您可以将所有 3 行代码写在一行中,如下所示:
randomFile mind maxd noe = randomRIO >>= writeFile "RFile.txt" . replicateM (fromInteger(noe ^ noe))
如果这对您来说像是胡言乱语,那么您需要学习很多东西。这是建议的路径:
- 如果还没有,请从头开始 Learn You a Haskell
- 然后了解如何 You could have invented Monads
- 然后详细了解如何使用randomness in Haskell
- 最后看看能不能完成20 intermediate Haskell exercises
我正在尝试将文件中的随机整数列表写入文件。这里writeFile
好像有问题。当我使用函数 randomFile
时,它显示 no instance for (Show (IO a0))
。我看到 writeFile
没有在屏幕上打印任何东西,但是 IO()
,所以当我调用函数 randomFile 1 2 3
时它说 no Instance for Show (IO a0)
但实际上我只想执行函数而不是必须打印任何东西,但我怎样才能避免这个问题。我可能在这里犯了很多错误。任何帮助。
import Control.Monad
import Control.Applicative
import System.Random
randNo mind maxd = randomRIO (mind,maxd)
randomFile mind maxd noe = do
let l=(replicate (fromInteger(noe ^ noe)) ( mind `randNo` maxd))
writeFile "RFile.txt" (show l)
我觉得你对IO是什么有误解。如果您还没有这样做,我强烈建议您通过 Input and Output section of Learn You a Haskell.
IO
与 print
没有任何关系。在 Haskell 中,由您自己的代码创建的每个内存条目都被视为 "pure",而触及计算机其余部分的任何条目都存在于 IO 中(除了一些例外,您将随着时间的推移了解)。
我们使用称为 Monad 的东西对 IO 进行建模。你做的时间越长,你就会了解得越多 Haskell。为了理解这一点,让我们看一些使用和不使用 IO 的代码示例:
noIOused :: Int -> Int
noIOused x = x + 5
usesIO :: Int -> IO Int
usesIO x = print x >> return (x + 5)
usesIO2 :: Int -> IO Int
usesIO2 x = do
print x
return (x + 5)
第一个函数是"pure"。第二个和第三个函数有一个 IO "effect",以打印到屏幕的形式出现。 usesIO
和 usesIO2
只是做同一件事的两种不同方式(它是相同的代码,但语法不同)。我将使用第二种格式,从这里称为 do
表示法。
以下是您可能产生 IO 效果的其他一些方式:
add5WithFile :: Int -> IO Int
add5WithFile x = do
writeFile "someFile.txt" (show x)
return (x + 5)
注意在那个函数中我们没有打印任何东西,我们写了一个文件。但是写入文件有一个副作用,并且会与系统的其余部分交互。所以我们 return 的任何值都必须包含在 IO 中。
addRandom :: Int -> IO Int
addRandom x = do
y <- randomRIO (1,10)
return (x + y)
在addRandom
中我们调用了randomRIO (1,10)
。但问题是 randomRIO 没有 return 和 Int
。它 return 是一个 IO Int
。为什么?因为为了获得真正的随机性,我们需要以某种方式与系统进行交互。为了解决这个问题,我们必须暂时去除 IO。这就是这一行的来源:
y <- randomRIO (1,10)
那个 <-
箭头告诉我们我们想要一个 y
值在 IO 之外。只要我们保持在 do
语法内,y
值就会成为 "pure"。现在我们可以像使用任何其他值一样使用它了。
例如,我们不能这样做:
let w = x + (randomRIO (1,10))
因为那会尝试将 Int
添加到 IO Int
。不幸的是,我们的 +
函数不知道该怎么做。所以首先我们必须将 randomRIO
的结果 "bind" 到 y
,然后才能将其添加到 x
.
现在让我们看看您的代码:
let l=(replicate (fromInteger(noe ^ noe)) ( mind `randNo` maxd))
writeFile "RFile.txt" (show l)
l
的类型实际上是IO a0
。它是 a0
因为你还没有告诉编译器你想要什么样的数字。所以它不知道你想要的是小数、双精度数、大整数还是其他什么。
所以第一个问题就是让编译器多了解一点你想要什么样的随机数。我们通过添加类型注释来做到这一点:
randNo :: Int -> Int -> IO Int
randNo mind maxd = randomRIO (mind,maxd)
现在你和编译器都知道 randNo
是什么类型的值了。
现在我们需要 "bind" do
符号内的那个值来暂时转义 IO。你可能认为这很简单,像这样:
randomFile mind maxd noe = do
l <- replicate (fromInteger(noe ^ noe)) ( mind `randNo` maxd)
writeFile "RFile.txt" (show l)
肯定会 "bind" IO Int
到 l
对吗?不幸的是没有。这里的问题是 replicate
是 Int -> a -> [a]
形式的函数。也就是说,给定一个数字和一个类型,它会给你一个该类型的列表。
如果你给 replicate
一个 IO Int
,它就会变成 [IO Int]
。这实际上看起来更像这样: List (IO Int)
除了我们使用 []
作为列表的语法糖。不幸的是,如果我们想 "bind" 一个 IO
值到 <-
的东西,它必须是最外面的类型。
所以你需要的是一种将 [IO Int]
变成 IO [Int]
的方法。有两种方法可以做到这一点。如果我们 put \[IO a\] -> IO \[a\]
into Hoogle 我们得到这个:
sequence :: Monad m => [m a] -> m [a]
正如我之前提到的,我们将 IO 概括为称为 Monad 的东西。这没什么大不了的,我们可以假装 sequence
有这个签名:sequence :: [IO a] -> IO [a]
并且它只是专门用于 IO 的东西。
现在你的函数将像这样完成:
randomFile mind maxd noe = do
l <- sequence (replicate (fromInteger(noe ^ noe)) ( mind `randNo` maxd))
writeFile "RFile.txt" (show l)
但是 sequence
后跟 replicate
是人们必须一直做的事情。所以有人去做了一个叫做 replicateM
:
replicateM :: Monad m => Int -> m a -> m [a]
现在我们可以这样写你的函数了:
randomFile mind maxd noe = do
l <- replicateM (fromInteger(noe ^ noe)) ( mind `randNo` maxd)
writeFile "RFile.txt" (show l)
对于一些真正的 Haskell 魔术,您可以将所有 3 行代码写在一行中,如下所示:
randomFile mind maxd noe = randomRIO >>= writeFile "RFile.txt" . replicateM (fromInteger(noe ^ noe))
如果这对您来说像是胡言乱语,那么您需要学习很多东西。这是建议的路径:
- 如果还没有,请从头开始 Learn You a Haskell
- 然后了解如何 You could have invented Monads
- 然后详细了解如何使用randomness in Haskell
- 最后看看能不能完成20 intermediate Haskell exercises