这一定是非常基本的东西。我不熟悉语法,这是我第一个最困难的问题。 下面的connection
返回 IO Connection
类型的内容 - 但我不明白 IO 和连接是如何连接的/这是什么意思。如果可以,请告诉此操作中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;
}
IO
是参数化类型(在Haskell中称为类型构造函数或在C#/Java中称为泛型(。在本例中String
是其类型参数。
Haskell中的IO String
将编写为Java/C#/C++中的IO<String>
。
你觉得这个该死的IO
是你的敌人?也去过那里。
但很快你就会发现IO
是你的朋友。这个可以称之为第一次启蒙。
认真地。假设您设法从 IO monad 中偷运了一Connection
。进一步假设有以下"函数":
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语句,以至于您不知道a(它们是否会运行以及b(以什么顺序运行。
因此,nice do 表示法,它保证(至少对于 IO monad(顺序执行。
(你可以显式使用>>=,但我保证,这不会很有趣。
IO 之所以存在,是因为创建连接涉及输入/输出,而不仅仅是纯代码。 正如其他人所说,您无法摆脱它。 但是在do表示法中,你可以让它看起来像已经消失了,并应用只需要一个Connection
的函数:
main = do
c <- connection
testQuery c
(假设您制作了类型 Connection -> IO Int
的testQuery
(
(<-)
是绑定运算符,它将应用(>>=) :: Monad m => m a -> (a -> m b) -> m b
,这将起作用,因为IO
有一个Monad
实例。