haskell - Haskell:如何在 do 块下使用 where 语句
问题描述
当我遇到一个我不明白的错误时,我正在用 Haskell 和它的 IO 制作一个程序。当我在 do 块之后使用 where 语句时,它不会做与没有 do 块相同的事情。
有效的程序是:
import Control.Monad
prog :: IO()
prog = do m <- getLine
n <- getLine
p <- getLine
replicateM_ (read m :: Int) (putStrLn n)
replicateM_ (read m :: Int) (putStrLn p)
但是当我用这样read m :: Int
的 where 语句替换时:
import Control.Monad
prog1 :: IO()
prog1 = do m <- getLine
n <- getLine
p <- getLine
replicateM_ (a) (putStrLn n)
replicateM_ (a) (putStrLn p)
where
a = read m :: Int
我得到错误:
Template.hs:23:21: error: Variable not in scope: m :: String
|
23 | a = read m :: Int
| ^
我已经查看了问题可能是什么,我认为这与 m 的类型有关,即IO String
. 我知道你必须保持在 IO 类型(一旦你在其中)才能使用字符串。但我不明白为什么“哪里”会“爆发”这种 IO 类型。据我了解,我给出的两个示例功能相同。首先,我认为编写没有 where 的程序无法修复错误,因为读取的函数来自类型read :: Read a => String -> a
,而我在第一个程序中的输入也是IO String
. 那么为什么我的第一个程序没有给我一个错误呢?有人可以解释我理解的错误以及如何修复我的程序以便我只需要执行read m :: Int
一次吗?只是一些关于如何在 do 块下使用 where 语句的提示也会有所帮助。
我遇到问题的原始程序更长且并非全部相关,因此我使用这个最小的工作示例来解释我的问题的本质。在我的原始程序中,where 后面有多个语句,所以我不想像在这个例子中那样替换它。
解决方案
块中的绑定do
对其后面的语句是不透明的where
,因此您不能引用语句do
内部块中定义的任何内容where
。您也不需要,因为您可以let
直接在内部使用do
:
prog1 = do m <- getLine
n <- getLine
p <- getLine
-- alternatively: [m, n, p] <- replicateM 3 getLine
-- use a let statement
let a = read m :: Int
replicateM_ a (putStrLn n)
replicateM_ a (putStrLn p)
推荐阅读
- python - GCFS 写入超出配额并引发 HTTP 错误 429
- css - 日期、金额和总计的 CSS 对齐方式
- symfony - Symfony 4如何设置全局参数以在树枝中使用
- c# - iTextSharp - 合并一批 PDF 字节数组
- pyspark - 如何为我的数据框创建一个新列,其值是由不同列的值组成的映射?
- qt - 如何更改 QML Dial 中的圆形进度条?
- node.js - 如何确定 SFTP 文件是否是 Node.js 中的目录?
- batch-file - 从文件夹中的文件标题中提取日期
- asp.net-core-2.0 - 处理 ASP.NET Core 中超出的最大请求长度
- c# - 如何编写 LINQ 查询以丢弃 CASE 语句 SQL 的 else 部分?