在Haskell IO中组合和拆分分配会阻止

时间:2016-08-28 16:00:26

标签: haskell io-monad

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

我发现只要一行就可以成功执行操作,但是当我为了便于阅读而尝试拆分为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,

1 个答案:

答案 0 :(得分:4)

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)

如果您想对readLnputStrLn操作进行排序,可以使用>>运算符(这是do在幕后执行的操作):

myinput :: IO ()
myinput = do
  mynum :: Int <- putStrLn "Please input a number." >> readLn
  print mynum
但是,大多数时候,这对于可读性来说并不是很好。 (a >> b也会在没有投诉的情况下放弃a的结果,而如果丢弃不是do { a; b }的内容,()会给编译器发出警告。)