在 Haskell IO do 块中合并和拆分赋值
Combining and splitting assignment in Haskell IO do block
我/认为/我在两个地方对语言有类似的误解,涉及变量赋值在 do 块中的工作方式,涉及 IO monad。你能帮我理解 (1) 是不是同样的误解,(2) 如何消除它(在回答中,如果你对这个主题有最喜欢的参考资料,也许特别明确)?
我发现当它是一行时我可以成功地执行一个操作,但是当我为了可读性而尝试分成两行时就不行了。
第一部分:将 1 行变成 2 行
为什么这样做有效?
ipg :: IO ()
ipg = do
conn <- connect defaultConnectInfo { connectHost = "0.0.0.0"}
res <- execute conn "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just"Test")
print res
但这行不通
ipg :: IO ()
ipg = do
conn <- connect defaultConnectInfo { connectHost = "0.0.0.0" }
q <- "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just"Test")
res <- execute conn q
print res
给我:
Couldn't match expected type ‘IO a0’
with actual type ‘q0 -> IO GHC.Int.Int64’
Probable cause: ‘execute’ is applied to too few arguments
In a stmt of a 'do' block: res <- execute conn q
第一个和第二个尝试将查询部分存储在 q 中的区别。
第二部分:将 2 行变成 1 行
为什么这样做:
myinput :: IO ()
myinput = do
putStrLn "Please input a number."
mynum :: Int <- readLn
print mynum
但这行不通吗?
myinput :: IO ()
myinput = do
mynum :: Int <- readLn $ putStrLn "Please input a number."
print mynum
给我
Couldn't match expected type ‘IO () -> IO Int’
with actual type ‘IO a0’
The first argument of ($) takes one argument,
在
execute conn "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just "Test")
,$
运算符的左边是execute conn "INSERT…"
,右边是MyRecord …
。也就是说,您使用三个参数调用 execute
:连接、查询和参数。这是第一个问题:
q <- "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just "Test")
res <- execute conn q
这里$
运算符左边是字符串"INSERT…"
,右边是参数。您正在尝试调用一个字符串,然后将结果作为第二个参数传递给 execute
.
如果 q
可能是某种表示两个参数的奇怪类型,但它可能不会是 IO a
。您只想用 let
命名一个值,而不是 运行 一个动作。
这应该有效:
ipg :: IO ()
ipg = do
conn <- connect defaultConnectInfo { connectHost = "0.0.0.0" }
let query = "INSERT INTO test (num, data) VALUES (?, ?)"
let parameters = MyRecord (Just 200) (Just "Test")
res <- execute conn query parameters
print res
myinput :: IO ()
myinput = do
mynum :: Int <- readLn $ putStrLn "Please input a number."
print mynum
这个没有多大意义。也许是对$
运算符的误解? $
主要是一种不使用括号来编写表达式的方法; f $ x
等同于f x
,但是$
的优先级较低,所以可以写f $ 1 + 2
而不是f (1 + 2)
。
无论如何,如果有帮助,我会粗略地为您翻译成 Python:
def myinput():
mynum = int(input(print("Please input a number.")))
print(mynum)
如果你想对 readLn
和 putStrLn
操作进行排序,你可以使用 >>
运算符(这就是 do
在幕后所做的):
myinput :: IO ()
myinput = do
mynum :: Int <- putStrLn "Please input a number." >> readLn
print mynum
不过,大多数时候这对可读性来说不是很好。 (a >> b
也会毫无怨言地丢弃 a
的结果,而 do { a; b }
会在丢弃不是 ()
的内容时给出编译器警告。)
我/认为/我在两个地方对语言有类似的误解,涉及变量赋值在 do 块中的工作方式,涉及 IO monad。你能帮我理解 (1) 是不是同样的误解,(2) 如何消除它(在回答中,如果你对这个主题有最喜欢的参考资料,也许特别明确)?
我发现当它是一行时我可以成功地执行一个操作,但是当我为了可读性而尝试分成两行时就不行了。
第一部分:将 1 行变成 2 行
为什么这样做有效?
ipg :: IO ()
ipg = do
conn <- connect defaultConnectInfo { connectHost = "0.0.0.0"}
res <- execute conn "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just"Test")
print res
但这行不通
ipg :: IO ()
ipg = do
conn <- connect defaultConnectInfo { connectHost = "0.0.0.0" }
q <- "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just"Test")
res <- execute conn q
print res
给我:
Couldn't match expected type ‘IO a0’
with actual type ‘q0 -> IO GHC.Int.Int64’
Probable cause: ‘execute’ is applied to too few arguments
In a stmt of a 'do' block: res <- execute conn q
第一个和第二个尝试将查询部分存储在 q 中的区别。
第二部分:将 2 行变成 1 行
为什么这样做:
myinput :: IO ()
myinput = do
putStrLn "Please input a number."
mynum :: Int <- readLn
print mynum
但这行不通吗?
myinput :: IO ()
myinput = do
mynum :: Int <- readLn $ putStrLn "Please input a number."
print mynum
给我
Couldn't match expected type ‘IO () -> IO Int’
with actual type ‘IO a0’
The first argument of ($) takes one argument,
在
execute conn "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just "Test")
,$
运算符的左边是execute conn "INSERT…"
,右边是MyRecord …
。也就是说,您使用三个参数调用 execute
:连接、查询和参数。这是第一个问题:
q <- "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just "Test")
res <- execute conn q
这里$
运算符左边是字符串"INSERT…"
,右边是参数。您正在尝试调用一个字符串,然后将结果作为第二个参数传递给 execute
.
如果 q
可能是某种表示两个参数的奇怪类型,但它可能不会是 IO a
。您只想用 let
命名一个值,而不是 运行 一个动作。
这应该有效:
ipg :: IO ()
ipg = do
conn <- connect defaultConnectInfo { connectHost = "0.0.0.0" }
let query = "INSERT INTO test (num, data) VALUES (?, ?)"
let parameters = MyRecord (Just 200) (Just "Test")
res <- execute conn query parameters
print res
myinput :: IO ()
myinput = do
mynum :: Int <- readLn $ putStrLn "Please input a number."
print mynum
这个没有多大意义。也许是对$
运算符的误解? $
主要是一种不使用括号来编写表达式的方法; f $ x
等同于f x
,但是$
的优先级较低,所以可以写f $ 1 + 2
而不是f (1 + 2)
。
无论如何,如果有帮助,我会粗略地为您翻译成 Python:
def myinput():
mynum = int(input(print("Please input a number.")))
print(mynum)
如果你想对 readLn
和 putStrLn
操作进行排序,你可以使用 >>
运算符(这就是 do
在幕后所做的):
myinput :: IO ()
myinput = do
mynum :: Int <- putStrLn "Please input a number." >> readLn
print mynum
不过,大多数时候这对可读性来说不是很好。 (a >> b
也会毫无怨言地丢弃 a
的结果,而 do { a; b }
会在丢弃不是 ()
的内容时给出编译器警告。)