【问题标题】:Combining and splitting assignment in Haskell IO do block在 Haskell IO 中合并和拆分分配 do block
【发布时间】:2023-03-19 02:11:01
【问题描述】:

我 /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,

【问题讨论】:

    标签: haskell io-monad


    【解决方案1】:

    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 操作进行排序,可以使用&gt;&gt; 运算符(这是do 在幕后所做的):

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

    不过,在大多数情况下,这对于可读性来说并不是很好。 (a &gt;&gt; b 也会毫无怨言地丢弃 a 的结果,而 do { a; b } 会在丢弃不是 () 的内容时给出编译器警告。)

    【讨论】:

    • 知道了,所以这些都是不相关的问题。第一个只是没有检查执行函数是否接受了 4 个参数,以及我需要查询的 python 习惯 = "myquery {}".format(args);执行(查询)。第二个需要一个顺序运算符。如果我需要括号来明确显示操作顺序,而不是使用 $,我将不得不这样做:mynum :: Int > readLn)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多