类型之间的空间是什么意思?

时间:2012-03-02 14:56:45

标签: mysql haskell

这必须是非常基本的东西。我不熟悉语法,这是我第一个最困难的问题。下面的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;
}

3 个答案:

答案 0 :(得分:4)

IO是参数化类型(在Haskell中称为类型构造函数,在C#/ Java中称为泛型)。在这种情况下,String是它的类型参数。

Haskell中的

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实例。