在Haskell IO中组合和拆分赋值做块 [英] Combining and splitting assignment in Haskell IO do block

查看:152
本文介绍了在Haskell IO中组合和拆分赋值做块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我/我/我在两个地方对语言有类似的误解,涉及变量赋值在涉及IO monad的块中的工作方式。你能帮助我理解(1)它是否是同样的误解,(2)如何清除它(在答案中,也许特别是如果你有关于这个问题的最喜欢的参考)?

我发现我可以在所有行都成功执行操作,但当我尝试将其分成2以便可读时,则无法成功执行操作。



第一部分:将1行转换为2



为什么这有效?

  ipg :: IO()
ipg = do
conn< - connect defaultConnectInfo {connectHost =0.0.0.0}
res< - 执行conn INSERT INTO test(num,data)VALUES(?,?)$ MyRecord(Just 200)(JustTest)
print res

但这不起作用

  ipg :: IO()
ipg = do
conn< - connect defaultConnectInfo {connectHost =0.0.0.0}
q< - INSERT INTO test(num,data)VALUES(?,?)$ MyRecord 200)(只是测试)
res< - 执行conn q
print r es

给我:

 无法与预期类型'IO a0'
匹配,实际类型为'q0 - > IO GHC.Int.Int64'
可能的原因:'execute'应用于太少的参数
在'do'块的语句中:res< - 执行conn q

第一个和第二个尝试将查询部分存储在q中的区别。



第二部分:将两行转换为1

为什么这样做:

  myinput :: IO()
myinput = do
putStrLn请输入一个数字。
mynum :: Int< - readLn
print mynum

但这不是工作?

  myinput :: IO()
myinput = do
mynum :: Int< - readLn $ putStrLn请输入一个数字。
print mynum

给我

 无法匹配预期的类型'IO() - > IO实际'
与实际类型'IO a0'
($)的第一个参数有一个参数,

$ b $在

 执行conn 数据)VALUES(?,?)$ MyRecord(Just 200)(JustTest)

中, $ 运算符的左边是执行connINSERT ...,右键单击<手边是 MyRecord ... 。也就是说,您使用三个参数调用 execute :连接,查询和参数。这是第一个问题:

  q < - INSERT INTO test(num,data)VALUES(?,?)$ MyRecord(只是200)(只是测试)
res< - 执行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)(JustTest)
res< - 执行conn查询参数
print res






  myinput :: IO()
myinput = do
mynum :: Int< - readLn $ putStrLn请输入一个数字。
print mynum

这个没有什么意义。也许这是对 $ 运算符的误解。 $ 主要是一种不使用圆括号的表达方式; f $ x 相当于 fx ,但 $ 优先级低,因此您可以写 f $ 1 + 2 而不是 f(1 + 2) p>

无论如何,我会将它松散地转换为Python,如果有帮助的话:

 print(mynum)
($输入(print(请输入一个数字。))
print(mynum)

如果您想对 readLn 和<$ c $进行排序c> putStrLn 操作,可以使用>> 操作符(这就是 do 正在幕后做):

  myinput :: IO()
myinput = do
mynum :: Int< - putStrLn请输入一个数字。 >> readLn
print mynum

尽管这在大多数情况下不太适合可读性。 ( a>> b )也会放弃没有抱怨的 a 的结果,而 ){a; b} 如果放弃不是()的东西,会给编译器警告。)


I /think/ I have a similar misunderstanding of the language in two places involving how variable assignment works in do blocks, involving the IO monad. Could you help me understand (1) is it the same misunderstanding, (2) how to clear it up (in an answer, and maybe specifically if you have a favorite reference on the subject)?

I find that I can perform an operation successfully when it is all one line, but not when I try to split into 2 for readability.

Part I: Turning 1 line into 2

Why does this work?

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

But this not work

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

Gives me:

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

The difference between the first and second being trying to store the query portion in q.

Part II: Turning 2 lines into 1

Why does this work:

myinput :: IO ()
myinput = do
  putStrLn "Please input a number."
  mynum :: Int  <- readLn  
  print mynum

But this not work?

myinput :: IO ()
myinput = do
  mynum :: Int <- readLn $ putStrLn "Please input a number."
  print mynum

Gives me

Couldn't match expected type ‘IO () -> IO Int’
            with actual type ‘IO a0’
The first argument of ($) takes one argument,

解决方案

In

execute conn "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just "Test")

, the left-hand side of the $ operator is execute conn "INSERT…", and the right-hand side is MyRecord …. That is, you're calling execute with three arguments: the connection, the query, and the parameters. That’s the first problem:

q <- "INSERT INTO test (num, data) VALUES (?, ?)" $ MyRecord (Just 200) (Just "Test")
res <- execute conn q

Here, the left-hand side of the $ operator is the string "INSERT…", and the right-hand side is the parameters. You're trying to call a string, then pass the result as the second argument to execute.

If q could be some strange type that represented two arguments, though, it probably wouldn’t be an IO a. You’re looking to just name a value with let, not run an action.

This should work:

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

This one just doesn’t make a lot of sense. Maybe it’s a misunderstanding of the $ operator? $ is mostly just a way to write expressions without using parentheses; f $ x is equivalent to f x, but the $ has low precedence, so you can write f $ 1 + 2 instead of f (1 + 2).

Anyway, I’ll loosely translate it into Python for you, if that helps:

def myinput():
    mynum = int(input(print("Please input a number.")))
    print(mynum)

If you want to sequence the readLn and putStrLn actions, you can use the >> operator (which is what do is doing behind the scenes):

myinput :: IO ()
myinput = do
  mynum :: Int <- putStrLn "Please input a number." >> readLn
  print mynum

That’s not very good for readability most of the time, though. (a >> b will also discard the result of a without complaint, whereas do { a; b } will give a compiler warning if discarding something that isn’t ().)

这篇关于在Haskell IO中组合和拆分赋值做块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆