Комбинирование и разбиение присваивания в блоке Haskell IO do
Я / думаю / у меня похожее неправильное понимание языка в двух местах, связанных с тем, как работает назначение переменных в блоках do, включая монаду IO. Не могли бы вы помочь мне понять (1) это то же недоразумение, (2) как разобраться (в ответе, и, может быть, конкретно, если у вас есть любимая ссылка на предмет)?
Я считаю, что могу успешно выполнить операцию, когда она состоит из одной строки, но не тогда, когда я пытаюсь разделить на 2 для удобства чтения.
Часть I: Превращение 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.
Часть II: Превращение 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 ответ
В
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 }
выдаст предупреждение компилятору, если отбросит что-то, что не ()
.)