没有合适的资源?快使用搜索试试~ 我知道了~
理论计算机科学电子笔记177(2007)185-200www.elsevier.com/locate/entcs使用持久谓词的惰性数据库访问*塞巴斯蒂安·菲舍尔InstitutfurInforormatikUniversitatKielOlshausenstraße 40,24098基尔,德国摘要程序员需要一种机制来存储应用程序特定的数据,以持久化多个程序运行。为了完成这项任务,他们通常必须处理存储特定的代码来访问文件或关系数据库。函数逻辑编程通过持久谓词为透明持久存储提供了一个自然的框架,即,谓词与外部存储的事实。我们扩展了以前的工作,持久化谓词的咖喱懒惰数据库访问。数据库查询的结果只会被应用程序读取。我们还提出了一种面向类型的方法来实现数据库和Curry值之间的转换,该方法基于一个低级别的惰性数据库接口来实现对持久谓词的惰性访问。保留字:Curry,数据库访问,动态谓词,惰性,持久性1介绍编程语言需要一些机制来存储在程序执行过程中持久存在的数据.内部数据需要保存和恢复,外部数据必须由应用程序表示和操作。例如,Web应用程序经常读取存储在数据库服务器上的数据,并以结构化的方式将其呈现给用户。关系数据库通常用于高效地访问大量存储的数据。在关系数据库中,数据存储在可分为行和列的表中。从逻辑编程的角度来看,数据库表可以被视为谓词的指定,将谓词的事实存储在其行中。在以前的工作[7,5,4]中,我们开发了一种在Curry中访问数据库的方法,其中数据库表被视为特殊谓词的动态指定规范是动态的,因为它可能在运行时更改。因此,这项工作得到了DFG在Ha 2457/5-1赠款下的部分支持。1571-0661 © 2007 Elsevier B. V.在CC BY-NC-ND许可下开放访问。doi:10.1016/j.entcs.2007.01.024186S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185谓词被称为动态谓词。其事实被持久存储的动态谓词,例如,在数据库中,称为持久谓词。我们的方法的原型实现的第一次尝试对于大型结果集来说是无效的,因为这些结果集在执行查询时被完全解析。因此,我们开发了一个惰性实现,它不读取未使用的结果。此实现包括两个部分:• 我们开发了一个低级别的惰性数据库接口,• 我们基于这个接口实现对持久谓词的惰性访问。第二部分最有趣的一点是关于数据转换。我们提出了一种面向类型的方法来转换存储在数据库中的值本文主要介绍实际工作。虽然我们稍微修改了库的界面,但我们并没有引入概念上的新颖性。然而,值得注意的是,我们可以使用高级声明性技术来实现相当技术性的目标。因此,我们得到了一个简洁的,可移植的和可维护的实现。本文的其余部分结构如下:在第1.1节中,我们通过回顾声明性编程语言中数据库访问的相关工作来激励持久谓词。在第2节中,我们提出了我们的数据库库的接口。我们将在第3节讨论惰性数据库访问的一个低级实现。我们在第4节中描述了一种面向类型的数据库和Curry值之间的转换方法,该方法用于基于低级接口实现对持久谓词的延迟访问。最后,第5节载有结论性意见。1.1 相关工作持久谓词的概念在[3]中引入,其中提供了基于数据库和文件的Prolog实现。持久谓词使程序能够存储从一个执行到下一个执行持久的数据,并且是透明存储的,即,程序的源代码不需要随存储机制而改变。然而,[3]中提出的实现有两个主要缺点:首先,对持久谓词的访问是使用边对象实现的。这是一个问题,因为在这种方法中,调用持久谓词的程序的行为[3]的另一个缺点是,它不支持事务。数据库通常在Web应用程序的上下文中使用,其中可能有许多进程同时访问数据库因此,事务是数据库库实际实现的关键特性。这两个问题都在[7]中得到了解决,其中数据库访问只能在IO monad [11]内部进行在基于复杂求值策略的函数逻辑编程语言的上下文中,消除副作用尤其重要[1]。[4]通过持久谓词的数据库实现扩展了[7]中提出的库我们通过惰性数据库访问改进了这个实现,并稍微简化了它的接口。第2节概括了我们库的接口,并提到了S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185187版本介绍[4]。Haskell的一个组合子库,用于用关系代数构造数据库查询,由[9]提供。它允许语法正确和类型安全的数据库访问实现。作者提供了一种通用的方法,将领域特定语言嵌入到高阶类型语言中,并将其应用于关系代数以访问关系数据库。 [9]第九节:cally将一种领域特定语言集成到Haskell编程语言中,持久谓词透明地将数据库访问集成到熟悉的编程范例中。2该数据库的库在我们的方法中,持久谓词由关键字persistent定义,因为它们的定义不是程序的一部分,而是外部存储的。程序员给出的唯一信息是类型签名和用于持久化的字符串参数,用于标识存储位置。下面定义的谓词存储表中的(有限多个)素数与数据库currydb中的素数:prime::Int-> Dynamicprime persistent“db:currydb.primes”存储位置以“db:“为前缀,表示它是一个数据库表。在冒号之后,数据库和表被一个句号分开。持久谓词的结果类型是Dynamic,这在概念上类似于Success(Curry中约束和普通谓词的结果类型)。Dy-动态谓词与其他谓词不同,以确保提供来访问它们的 从概念上讲,Dynamic类型应理解为具有单值-就像Success是一个具有单值success的数据类型。间 -最后,数据类型存储关于如何访问外部存储的事实的信息。该信息由第2.2节中提供的实质等同规范和组合子引入。2.1基本操作存储在数据库中的持久谓词的基本操作是断言以插入新事实,撤回以删除和查询以检索它们。由于持久谓词的定义会随着时间的推移而变化,因此它们的访问只能在IO monad内部进行,以提供显式的求值顺序。要操作持久谓词的事实,assert::Dynamic->IO() retract::Dynamic->IO()提供。从概念上讲,这些函数将全局知识库作为一个副作用进行修改:assert将新的事实插入知识库,retract将其删除。assert和retract的参数不能包含自由变量,188S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185因此,只允许断言和撤回基本事实。如果数据库谓词的参数不为基础,则对assert或retract的调用将挂起,直到它们为基础。请注意,目前,Curry仅通过并发合取运算符()::成功->成功->成功类似于Concurrent Haskell [10]的Curry扩展支持并发i/o操作,可以利用此功能进行同步。我们可以定义一个替代版本的retract,它不会在部分实例化的参数上挂起,而是从数据库中删除所有匹配的事实,而不会将结果绑定传播到程序。这些绑定将被 封 装 在 撤 回 的 调 用 中 。 然 而 , 这 种 行 为 可 以 使 用 下 面 定 义 的getDynamicSolutions来实现,更重要的是,如果对所有要收回的调用都在内部进行封装,那么收回的实现将变得不必要,即,对于那些不涉及自由变量的人能力。此外,对于assert的实现,似乎不存在类似的替代方案。初看起来,将未知部分表示为空值似乎是合适的。然而,如果所有的自由变量都表示为空值,那么关于哪些变量是相同的信息就会丢失,因此,挂起或失败似乎对撤回更实用,并且是断言的唯一合理选项。我们选择了suspension来支持Curry与并发相关的可能扩展。对持久谓词的查询可以有多个非确定性计算的解。为了封装搜索,getDynamicSolutions::(a -> Dynamic)-> IO [a]采用动态谓词抽象,并返回满足抽象的所有值的列表,类似于结果类型为Success的谓词的getAllSolutions。功能getDynamicSolution::(a-> Dynamic)-> IO(Maybe a)只能用于查询一个解决方案。请注意,如果getDynamicSolutions是惰性的,则不需要此函数。但是在严格的实现中,所有的解都是提前计算的,即使程序只需要结果列表的头部。不幸的是,并非所有Curry实现都支持延迟封装搜索,我们只能为存储在数据库中的谓词提供它。还要注意,只提供了对动态谓词的封装访问。动态谓词不能像普通谓词那样用于防护中,因此不会导致程序的不确定性行为。2.2组合持久谓词通常需要同时从多个持久谓词查询信息,或者必须使用布尔条件限制查询。为了组合几个持久谓词,我们提供了两种不同形式的合取。一个是组合两个Dynamic类型的值,类似于普通约束的function()S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185189另一个是将Dynamic谓词与布尔条件组合在一起(<>)::动态->动态->动态(|>)::Dynamic -> Bool -> Dynamic这些组合子可以用来构造类似于典型数据库查询的动态例如,抽象\(x,y)->质数x>质数y|> x+2 == y类似于SQL查询选择tab1.prime,tab2.primeFROMprimes AStab1,primes AStab2其中tab1.prime+ 2 =tab2.prime转换成SQL依赖于SQL中存在的非常少的原始特性。带有where子句的简单select语句用于查询持久谓词的事实由于没有组合子来定义具有聚合参数的谓词-例如另一个参数的总和,平均值,最小值此外,我们的实现不会生成嵌套查询和having-ororder-by-子句。我们不提供聚合特性,因为不清楚如何对具有聚合参数的谓词执行断言聚合只有合理查询,因此必须显式编码。值可以被访问为如果相应的参数是Maybe类型,则为Nothing。如果不是,空值被表示为自由变量.[5,4]中讨论了一个详细的转换方案,包括将附加到持久谓词的布尔条件转换为高效SQL查询的机制。2.3交易由于对持久谓词的定义所做的更改对使用相同谓词的其他程序立即可见,因此需要事务来声明原子操作。由于数据库系统通常支持事务,所提供的功能依赖于数据库事务支持:transaction:: IO a -> IO(Maybea)abortTransaction:: IO atransaction函数用于启动transaction。给定的i/o操作以原子方式执行,如果i/o操作失败或使用abortTransaction显式中止,则返回Nothing。不支持嵌套事务,这会导致运行时错误。我们简化了[4]的接口,删除了transactionDB函数,该函数需要一个数据库名称来执行事务。现在,事务被指定为函数transaction,而不管它们是否190S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185是否使用数据库谓词,并且事务在当前进程已知的所有数据库中执行这是否是性能损失取决于所涉及的数据库系统中事务的实现。通常,不接触任何表的事务不会阻塞访问数据库的其他进程。实际上,一个进程通常不会访问不同的数据库系统,因此简化的接口很少会导致任何性能开销。3惰性数据库访问虽然复杂的限制可以使用合取组合符(<>)和(|>),数据库查询可能仍然有很大的结果集。如果程序员只访问部分结果,那么从数据库中检索所有结果是不必要的开销。在[ 4 ]中提出的实现通过标准i/o与数据库通信,并且总是在将其提供给应用程序之前解析完整的结果集。结果证明,这对于大型结果集来说是不够的因此,我们开发了一种替代实现。本文中给出的实现在调用getDynamicSolutions时不查询完整的结果。相反地,它只检索一个句柄,该句柄用于在需要结果时查询结果这种方法的优点是显而易见的:对getDynamicSolutions的调用只会导致可以忽略不计的延迟,因为它只从数据库中检索一个句柄,而不是整个结果集此外,应用程序不需要的结果不会从数据库中查询因此,仅对读取结果造成延迟被程序消耗-没有结果被提前查询。如果结果是按需读取的,则重要的是它们独立于何时需要它们。特别是,结果不能被查询和结果消费之间发生的表更新所影响。该属性由数据库系统确保。从概念上讲,当查询产生句柄并且所有结果都对应于此快照时,将创建数据库的快照。因此,延迟读取查询的事实并不影响相应的结果集关系数据库系统允许我们通过API来检索查询的结果集在本节中,我们将展示如何从Curry程序访问此API。访问数据库API的一种可能性是使用外部函数。然而,实现它们是一项复杂的任务,更重要的是,每个Curry实现都需要重新编码外部函数,因此尽可能避免它们是一个好主意。3.1咖喱港口Java支持多种数据库系统。Curry支持使用ports [6]的分布式编程,并且可以将此概念移植到Java中,并编写涉及Curry和Java程序的分布式应用程序。因此,如果我们可以使用Curry与Java程序进行通信,我们就可以在Curry中访问Java支持的所有数据库系统我们使用端口实现了数据库访问,以获得一个高级的、可维护的、S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185191和可移植的Curry实现,受益于Java对不同数据库系统的广泛支持我们不会讨论如何在Java中实现端口和数据库访问,而是关注我们实现的Curry部分。我们将集中讨论端口以及如何使用它们来建模惰性数据库接口。一个端口是一个消息的多重集合,它被限制为恰好包含指定列表的元素有一个谓词openPort:: Port a -> [a] ->成功它为类型A的消息创建端口。通常,openPort是以自由变量作为参数调用的,第二个参数是通过向第一个参数发送消息来实例化的。客户端可以使用send:: a -> Port a -> Success由于消息可能包含可以由服务器绑定的自由变量,因此不需要在端口上使用receive函数:如果客户端需要从服务器接收应答,它可以在其请求中包括自由变量,并等待服务器绑定该变量。要在不同的程序之间共享端口,可以在网络上访问I/O操作openNamedPort:: String -> IO[a]打开一个全局可访问的端口,并返回发送到该端口的消息列表。I/O操作connectPort:: String -> IO(Port a)返回在给定名称下注册的端口。最后两个函数破坏了端口通信的类型安全,因为它们的返回值是多态的。 谓词openPort和send确保只有类型正确的消息被发送到端口或从端口接收。但是,使用openNamedPort和connectPort,可以将类型不正确的消息发送到端口。 函数openNamedPort创建一个未指定类型的消息流,并且可以发送到由connectPort创建的端口的消息类型也是未指定的。如果端口用于通过网络进行通信,则此通信不再是类型安全的。因此,我们必须自己仔细建立类型正确的我们库的用户不关心这些问题,因为基于端口的接口没有导出。3.2数据库的惰性接口在本节中,我们将描述用于与实现数据库访问的Java程序进行通信的消息,以及使用这些消息实现惰性数据库接口的函数。这个接口并不是为应用程序设计的,而只是在内部用于持久谓词的实现。为了与Java程序进行通信,我们需要一个数据类型,192S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185通过端口发送的消息和存储在数据库表中的值的数据类型。Curry进程必须能够打开和关闭数据库连接,并发送insert-、delete-或commit-语句。然而,关于惰性数据库访问的最有趣的消息是那些与查询和结果检索有关的消息。如前所述,句柄必须作为查询的结果返回。此外,必须能够检查是否有更多的结果对应于句柄,如果有,则查询结果集的另一行。因此,我们定义了以下数据类型:数据DBMessage=打开字符串DBHandle|更新DBHandle字符串| 查询DBHandle字符串ResultHandle| EndOfResults DBHandle ResultHandle Bool| NextRow DBHandle ResultHandle [DBValue]| 关闭DBHandletype DBHandle = Inttype ResultHandle = Int数据DBValue= NULL|布尔布尔|INT Int| 浮动|CLOB字符串|时间ClockTimetypeConnection=(端口DBMessage,DBHandle)连接由类型为(PortDBMessage)的端口和类型为DBHandle。数据类型DBValue包装不同SQL列类型的值。SQL支持各种不同的列类型,我们选择了一个合理的小表示作为代数数据类型。为了得到一个小的表示,我们表示不同SQL类型的值作为相同Curry类型的值。例如,DOUBLE、FLOAT、REAL、. . .都表示为Curry中的浮点值。SQL支持特殊的数据库DATE、TIME和DATETIME,用于表示为ClockTime类型的包装值的日期 虽然包含列类型是一个抽象,它对于Curry中的透明数据库访问足够详细我们实现的核心部分是数据类型DBMessage的定义。定义的消息用于以下目的:• (Openspec db)打开一个到指定数据库的新连接,db用一个代表连接的整数表示。• (更新数据库sql)在数据库中执行SQL语句sql,db不返回结果。• (Querydb sql result)用于返回结果的查询。 请注意,只返回表示结果集的整数。S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185193• (EndOfResultsdb result empty)检查结果集是否为空,• (NextRow数据库结果行)从非空结果集中查询一行,• (Closedb)关闭指定的连接。作为使用此数据类型通过端口与数据库服务器通信的简单示例,请考虑以下定义:endOfResults:: Connection-> ResultHandle->Bool endOfResults(p,db)r|send(EndOfResults dbrempty)p=ensureNotFree emptywhere empty free对ensureNotFree的调用挂起,直到其参数被绑定,并用于等待从服务器返回的答案。函数endOfResults和NextRow-消息可用于定义函数query:: Connection-> String->[[DBValue]]它执行SQL查询,并以惰性方式返回结果集中所有行的列表。关键思想是延迟对实际行的查询,直到程序需要它们。函数lazyResults接受一个连接和一个结果句柄,并延迟返回一个行列表,实现如下:lazyResults:: Connection-> ResultHandle->[[DBValue]] lazyResults(p,db)r| endOfResults(p,db)r=[]| 否则=send(NextRow dbrrow)&>(ensureNotFreerow:lazyResults(p,db)r)其中行自由通过发送NextRow消息按需查询每一行,如果endOfResults返回True,则结果集为空。请注意,我们需要每行的内容,当结果列表的相应构造函数(:)被要求时。由于每次调用endOfResults都会将结果指针推进到下一行,因此我们可能无法在以后请求前一行的内容最后,可以使用Query-message和函数lazyResults来实现函数query:query:: Connection-> String->[[DBValue]] query(p,db)sql| send(Query db sql resultHandle)p= lazyResults(p,db)(ensureNotFreeresultHandle)其中resultHandle自由请注意,所呈现的函数不是i/o操作。虽然i/o是由我们与之通信的Java应用程序执行的,但通信本身是通过IO monad之外的send-constraints完成的。因此,所提供的功能可以被认为是不安全的,需要小心使用。需求驱动的数据库访问194S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185如果没有这种不安全的功能,就无法实现。回想一下,例如,在IO monad中没有不安全的功能,就不可能实现惰性readFile请注意,所提供的函数不是我们数据库库的一部分它们只在持久谓词的实现中内部使用函数查询可用于定义getDynamicSolutions的惰性版本,以按需检索持久谓词抽象的所有解决方案。它的实现必须考虑从异构部分组合的谓词。存储的等同器械数据库中的数据可以自由地与存储在文件中的其他数据或存储在主存储器中的事实相结合。细节不在本文讨论范围之内。然而,这些细节的一个有趣的方面是如何在数据类型DBValue和Curry值之间自动转换。解决这个问题的一种方法,采用类型-面向数据库规范在第4节中讨论。然而,我们考虑一个示例,它演示了使用持久谓词的惰性数据库访问main =执行assert(foldr1(>)(map prime [3,5,7]))(p:ps)-getDynamicSolutions prime print p收缩(主5)打印(打印头ps)这个程序的输出是:35第一行将三个素数插入数据库。在下一行中,这些质数是从数据库中查询的-至少在概念上是这样。事实上,只有第一个素数是从数据库中读取的,因为它是模式(p:ps)所要求的。 下一行在屏幕上打印所需的质数。 然后,值5从数据库中删除这并不意味着还没有因为数据库维护每个结果集的一致快照。因此,在下一行中,当要求并从数据库中查询下一个素数时,值5仍然是在5被删除之前查询的结果集的元素不从数据库中查询值7,因为程序.通过调用main执行的通信如下所示:发送到数据库服务器的消息向左对齐,表示服务器响应的变量绑定向右对齐。自由变量在通信期间表示为项(VARn),其中n是整数,识别变量。开放“jdbc:mysql://localhost/currydb”(VAR0)(VAR0)绑定到0更新0“进入primesVALUES(3),(5),(7)”查询0“SELECTprime FROMprimes”(VAR0)(VAR0)绑定到0EndOfResults 0 0(VAR 0)(VAR 0)绑定到FalseS. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185195NextRow 0 0(VAR0)(VAR0)绑定到[INT3]更新0“从primes开始,其中prime = 5”EndOfResults 0 0(VAR 0)(VAR 0)绑定到False下一行0 0(VAR0)(VAR0)绑定到[INT5]不返回结果的SQL语句将在更新消息中发送到数据库。 Open-和Query-消息分别包含一个绑定到数据库和结果句柄的自由变量。 在这个例子中,两个句柄都等于0。EndOfResults-消息在示例中发送两次,并且还包含一个自由变量,该变量两次都绑定为False,因为程序不需要所有结果。NextRow-消息中的自由变量绑定到列表,该列表表示每次发送消息时当前所需的素数延迟访问与事务一起使用效果很好,如以下稍微修改的示例所示:main只是ps)(map prime [3,5,7]))(p:ps)-getDynamicSolutions prime print pretract(prime5)return ps)print(head在这里,素数谓词的修改在事务内部完成,第二个素数在事务提交后被要求。修改后的程序的输出与原始程序的输出相同,即, 仍然从数据库查询值5,尽管在要求它之前已经提交了它的收回。我们需要显式地返回素数列表的尾部作为事务的结果ps变量ps在事务外部不可见如果交易被中止,我们就不能要求更多的素数,因为素数列表的尾部将不可用。在流产的情况下,交易的结果不会是什么,只是p s'。通过调用main'look生成的comminication如下所开放“jdbc:mysql://localhost/currydb”(VAR0)(VAR0)绑定到0更新0“START TRANSACTION”更新0“进入素数值(3),(5),(7)”查询0“SELECTprime FROMprimes”(VAR0)(VAR0)绑定到0EndOfResults 0 0(VAR 0)(VAR 0)绑定到FalseNextRow 0 0(VAR0)(VAR0)绑定到[INT3]更新0“从primes开始,其中prime = 5”更新0“提交”EndOfResults 0 0(VAR 0)(VAR 0)绑定到False下一行0 0(VAR0)(VAR0)绑定到[INT5]196S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185惰性访问与事务管理的交互由数据库服务器处理。在我们的实施过程中,我们不必采取特殊的预防措施。特别是,当我们返回查询结果的句柄时,我们不会显式存储一致的快照。我们更依赖于数据库系统只返回与查询时间点一致的结果。我们与之通信的Java程序只是为Java数据库接口(JDBC)提供的某些数据库操作定义包装函数JDBC支持三种不同的方式来查询数据库查询的结果。它们都采用了游标的概念,游标在结果集的行上导航。第一种方法只允许一个接一个地检索结果,即,光标只能向前移动一步一步 其他的支持所谓的可滚动结果集,允许同时向前和向后移动多个步骤可滚动结果集的区别在于,在结果句柄打开时对数据库所做的更改 不敏感的结果集不显示此类更改敏感的结果集。 通常,可滚动结果集的效率低于一种只支持对结果的顺序访问的方法。因此,我们在实现中采用了不可滚动的结果集。我们经历过这种类型的结果集是不敏感的,这对于延迟访问至关重要但是,这可能因不同的数据库服务器而异因此,可能需要在其他数据库系统中使用可滚动、不敏感的我们相信,即使是使用可滚动结果集的实现也会比我们最初的基于解析完整结果集的字符串表示的方法[4,5]4面向类型的数据库规范为了实现访问持久谓词的操作,我们需要在Curry值和DBValue类型的值之间进行转换。特别是,要使用函数getDynamicSolutions实现封装搜索,我们需要解析第二节中介绍的函数查询返回的[DBValue]第3.2条。在本节中,我们将描述一种使用面向类型的数据库规范来解决这个问题的方法类似的技术已经在[8]中用于构建Web用户界面。使用第2节中介绍的关键字persistent声明持久谓词的特殊语法被转换为对特殊函数persistentn的调用,其中n是声明谓词的arity而不是质数,我们认为一个稍微复杂一点的持久谓词的例子,它存储关于人的信息:dataName = Name String Stringtype YearOfBirth= Intperson::Name-> YearOfBirth ->Dynamic person persistent“db:currydb.persons”S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185197一个人有一个名字,由一个名字和一个姓氏组成,出生年份被存储,以便能够计算人的年龄。我们使用给定的类型签名和运行时系统可用的附加信息(关于数据库驱动程序)来在程序加载时转换持久谓词声明。持久谓词person的声明在内部转换为person::Name-> YearOfBirth->Dynamic person= persistent2“jdbc:mysql://localhost/currydb persons”(cons2Name(string“last”)(string“first”))(int“born”)该声明声明person是一个持久谓词,有2个参数存储在本地机器上MySQL数据库的currydb表persons中。表persons有3列。 前两列人的第一个论点。第三列第二个论点是人。规格cons2Name(string“last”)(string“first”)int“born”类似于人的论证类型的结构。第一个类似于具有两个字符串参数的构造函数,第二个表示整数。原始规范string和int的字符串参数表示存储相应值的列名。类似上面显示的声明是从提供的类型信息自动生成的。但是,这种自动转换会选择不太直观的列名。所呈列的规格有不同用途。首先,它们存储有关相应列名和SQL列类型的信息。其次,它们存储在数据库和Curry值之间转换的函数。我们为这些规范定义数据类型DBSpec如下:data DBSpec a = DBSpec[String] [String](ReadDBa)(ShowDBa)type ReadDB a =[DBValue]->(a,[DBValue])类型ShowDB a = a->[DBValue]->[DBValue]实际上,这些类型在实际实现中要复杂一些。然而,所提出的类型对于这种描述是足够的DBSpec的前两个组件存储列名和类型。 类型(ReadDBa)的函数是一个解析器,它接受数据库值的列表,并返回类型a的值以及其余未解析的数据库值。一个类型为(ShowDBa)的函数接受一个类型为a的值和一个数据库值的列表,并将给定值表示为数据库值来扩展该列表。我们可以定义上面给出的原始组合子intint:: String ->DBSpec Intintname = DBSpec [name][“INT”] rd sh198S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185哪里rd(NULL : xs)=(letx free inx,xs)rd(INT n: xs)=(n,xs)sh n xs =(INT(ensureNotFree n):xs)整数解析器从数据库值列表中读取一列,如果它是空值,则返回一个自由变量。show函数使用整数值扩展给定的数据库值,并在自由变量时挂起。其他基本类型的数据库规范,即string,float,bool和time,可以类似地定义。复杂的数据表可以由多个列表示。回想一下上面介绍的一个人的名字的具体说明:cons2 Name(string“last”)(string“first”)combinatorcons2可以定义如下:cons2::(a-> b ->c)-> DBSpec a -> DBSpec b -> DBSpec ccons2 cons(DBSpec nsatsa rda sha)(DBSpec nsbtsb rdbshb)= DBSpec(nsa++nsb)(tsa++tsb)rdsh其中缺点a b =缺点a brd = rda />=\a-> rdb />=\b-> ret(Cons a b)sh(Cons a b)= sha a. 舍布这个combinator接受一个二进制构造函数cons作为第一个参数。后面的参数是与所提供的构造函数的参数类型相对应的数据库规范。所提供的具体产品的名称和类型信息新的规范中合并了一些内容,即,构造函数的参数存储在数据库表的后续列最后,read和show函数是由参数的read和show函数构造的。 我们使用预定义函数composition(.)::(b->c)->(a->b)->(a->c)为read函数定义show函数和一元解析器组合子:(/>=)::ReadDB a ->(a -> ReadDB b)->ReadDB b rda />= f= uncurry f. RDAret:: a ->ReadDBa ret a xs=(a,xs)函数uncurry::(a->b->c)->(a,b)-> c将二元函数转换为对函数。show函数的定义乍一看可能会令人困惑:它匹配一个值(Cons ab),其中Cons是一个局部定义的函数,等于作为第一个参数提供的构造函数cons 除了建筑师,在库里也定义了可以在模式声明中使用函数符号[2]。这允许我们为任意数据集定义基于类型的组合子,而不仅仅是特定的数据集。我们S. Fischer/Electronic Notes in Theoretical Computer Science 177(2007)185199提供类似的组合子cons1,cons3,cons4,. 对于不同的构造器。所呈现的组合子允许用于在数据库和Curry值之间转换的数据库规范的简洁声明这些声明是在程序加载时自动引入的。但是,如果程序员想控制列名,他也可以自己引入它们,例如,如果他想访问现有的数据库表。生成的转换器内部用于实现基于第3.2节中介绍的低级惰性数据库接口对持久谓词的惰性访问。面向类型的组合子的思想似乎适用于各种应用程序。它们将泛型编程的优点带到了一种没有特定泛型编程特性的语言中。我们计划在未来更详细地探讨这种联系。5结论我们描述了Curry的函数逻辑数据库库的一个惰性实现该库基于持久谓词,其允许透明地访问外部存储的数据,即,没有特定的存储代码。我们扩展了[4],实现了惰性数据库访问,并通过丢弃transactionDB函数简化了事务的声明。我们提出了一个实现懒惰的数据库访问,这是既可移植的,因为它是用Curry实现的,使用端口的概念[6],而不是使用外部函数集成到运行时系统中。此外,我们的实现支持各种数据库系统,因为它受益于Java对不同数据库系统的广泛支持。 使用基于端口的惰性数据库接口,我们为Curry实现了一个低级惰性数据库接口。在此基础上,我们开发了面向类型的转换器规范,以实现getDynamicSolutions的惰性版本,该版本封装了Dynamic懒洋洋地抽象。 应用程序不需要的值是没有事先从数据库中查询到。虽然我们没有介绍有关数据库管理的概念上的新颖性,但我们证明了相当技术性的实现目标效率-可以使用高级编程技术来实现。函数逻辑编程足够强大,可以使用函数逻辑编程技术透明、高效地将数据库编程集成到其编程范式引用[1] Antoy , S. , R. Echahed 和 M. Hanus , A needed narrowing strategy , Journal of the ACM47(2000),pp. 776-822[2] Antoy , S. 和 M. Hanus , Declarative Programming with Function Patterns , in : Proceedings oftheInternational Symposium on Logic-based Program Synthesis and Transformation (LOPSTR '05)(2005),pp. 6比22200S. Fischer/Electronic Notes in Theoretica
下载后可阅读完整内容,剩余1页未读,立即下载
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://profile-avatar.csdnimg.cn/default.jpg!1)
cpongm
- 粉丝: 4
- 资源: 2万+
上传资源 快速赚钱
我的内容管理 收起
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助
![](https://csdnimg.cn/release/wenkucmsfe/public/img/voice.245cc511.png)
会员权益专享
最新资源
- 利用迪杰斯特拉算法的全国交通咨询系统设计与实现
- 全国交通咨询系统C++实现源码解析
- DFT与FFT应用:信号频谱分析实验
- MATLAB图论算法实现:最小费用最大流
- MATLAB常用命令完全指南
- 共创智慧灯杆数据运营公司——抢占5G市场
- 中山农情统计分析系统项目实施与管理策略
- XX省中小学智慧校园建设实施方案
- 中山农情统计分析系统项目实施方案
- MATLAB函数详解:从Text到Size的实用指南
- 考虑速度与加速度限制的工业机器人轨迹规划与实时补偿算法
- Matlab进行统计回归分析:从单因素到双因素方差分析
- 智慧灯杆数据运营公司策划书:抢占5G市场,打造智慧城市新载体
- Photoshop基础与色彩知识:信息时代的PS认证考试全攻略
- Photoshop技能测试:核心概念与操作
- Photoshop试题与答案详解
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035111.png)
安全验证
文档复制为VIP权益,开通VIP直接复制
![](https://csdnimg.cn/release/wenkucmsfe/public/img/green-success.6a4acb44.png)