这必须是非常基本的东西。我不熟悉语法,这是我第一个最困难的问题。下面的connection
会返回IO Connection
类型的内容 - 但我不明白IO和Connection是如何连接的/它是什么意思。如果可以,请说明此操作中IO的用途是什么,以及如何将其松开。
{-# LANGUAGE OverloadedStrings #-}
import Database.MySQL.Simple
-- This returns `IO Connection'
connection :: Connection
connection = do
c <- connect defaultConnectInfo
{ connectPassword = "password",
connectDatabase = "database" }
return c
-- Possibly need to do something to `c', but don't know what
first_table :: IO String
first_table = do
[Only i] <- query_ connection "show tables"
return i
test_query :: IO Int
test_query = do
[Only i] <- query_ connection "select 2 + 2"
return i
但是,我的最终目标是找到只能连接到数据库一次的方法,将连接句柄存储在某处并在调用第一个或第二个函数时重用它。我无法理解如何做到这一点(例如,在Erlang中,我需要打开一个单独的进程并等待请求连接的消息,这非常麻烦和不舒服 - 所以我希望,我不会需要经历这样的事情......)。
提前致谢。
编辑:
{-# LANGUAGE OverloadedStrings #-}
import Database.MySQL.Simple
-- I need, instead of this function something that only connects once to the databse.
connection :: IO Connection
connection = do
c <- connect defaultConnectInfo
{ connectPassword = "password",
connectDatabase = "database" }
return c
first_table :: IO String
first_table = do
c <- connection
[Only i] <- query_ c "show tables"
return i
test_query :: IO Int
test_query = do
c <- connection
[Only i] <- query_ c "select 2 + 2"
return i
将connection
想象成是,好吧,让它成为Java的变化:
public Connection getConnection() {
if (connection == null) connection = /* JDBC does it's dirty job
and creates connection handle */
return connection;
}
答案 0 :(得分:4)
IO
是参数化类型(在Haskell中称为类型构造函数,在C#/ Java中称为泛型)。在这种情况下,String
是它的类型参数。
IO String
将在Java / C#/ C ++中编写为IO<String>
。
答案 1 :(得分:3)
你觉得这个该死的IO
是你的敌人?去过那里。
但很快你就会发现IO
是你的朋友。这个可以称之为第一个启蒙。
严重。假设您设法将Connection
走私出IO monad。进一步假设有以下“功能”:
update :: Connection -> Table -> Key -> Column -> Value -> ()
insert :: Connection -> Table -> Key -> {(Column, Value)] -> ()
当人们想到这样的表达式的语义时,问题就变得明显了:
let
ins1 = insert conn foo "bar" [("age", 42)]
upd1 = update conn foo "bar" "age" 43
upd2 = update conn foo "bar" "age" 44
in (ins1, upd1, upd2)
首先,定义中的等号与数学相同。定义是一个定义,不是一个“执行”定义右侧的命令。 其次,语义是非严格的。在这种情况下,这意味着要构造3元组,我们不必扩展定义或以某种方式评估它们。反之。事实上,我们不能在他们的结果真正非常需要之前对它们进行评估。
然后,IO类型的一种合理化:IO类型允许您在一个设置中对事物进行顺序化,其中值通常以看似随机的顺序或甚至并行地进行评估。
当然,你不想以一种你不知道的方式执行一些SQL语句,如果它们将被运行,b)以什么顺序运行。
因此,良好的符号,保证(至少IO monad)顺序执行。
(您可以明确使用&gt;&gt; =但我保证,这将不会有趣。)
答案 2 :(得分:2)
IO就在那里,因为创建Connection涉及输入/输出,而不仅仅是纯代码。正如其他人所说,你无法摆脱它。但是在表示法中,你可以让它看起来像它已经消失了,并应用只需要Connection
的函数:
main = do
c <- connection
testQuery c
(假设您testQuery
类型为Connection -> IO Int
(<-)
是绑定操作符,它将应用(>>=) :: Monad m => m a -> (a -> m b) -> m b
,这将起作用,因为IO
有一个Monad
实例。