繁体   English   中英

如何使用公共变量参数清晰地定义包含函数的Haskell模块?

[英]How to cleanly define a Haskell module containing functions with a common variable parameter?

我正在尝试编写一个Haskell模块,该模块使用库haxr定义远程XML-RPC API的函数。 以下是haxr的文档建议您如何在url上定义一个调用examples.add的Haskell函数:

add :: String -> Int -> Int -> IO Int
add url = remote url "examples.add"

像这样叫:

server = "http://localhost/~bjorn/cgi-bin/simple_server"
add server x y

如果我有一个或两个XML-RPC方法(我不需要一个单独的模块),这对我来说似乎没问题。 但是,代码中的server重复是一个问题,因为我有近100个函数。 我无法在模块中定义server ,如下所示:

someRemote :: Remote
someRemote = remote "http://example.com/XMLRPC"

add :: Int -> Int -> IO Int
add = someRemote "examples.add"

因为如果URL对于使用它的代码是灵活的,则不能对其进行硬编码。 我也无法将someRemote定义为函数的参数,因为它具有相同的重复问题。

Haxr的例子没有提供如何解决这个问题的线索。

我通常用命令式OOP语言(即Java,Python)编写程序。 如果我使用这些语言,我会定义一个带有构造函数的类,它使用server ,所有函数都使用对象实例的server变量,而不是询问调用代码。

我在Haskell中找到了相同的东西,但我似乎不知道找到它的正确关键字。 类型类似乎不是答案。 我可以写一个更高阶的函数来返回部分应用的函数,但是解压缩它们会更加丑陋。

我不太确定“重复服务器”实际上是那么糟糕。 当然,你永远不应该复制一个冗长的文字,但对于一个不会使代码混乱并且易于替换的单个变量名称,这应该不是什么大问题。

但是当然,通过将共享变量附加到您正在使用的monad中,您可以轻松避免这种重复,类似于将其附加到OO类对象的方式。 那叫做读者

import Control.Monad.Trans.Reader
type RemoteIO = ReaderT String IO  -- or perhaps `ReaderT Remote IO`

add :: Int -> Int -> RemoteIO Int
add x y = do
   url <- ask
   lift $ remote url "examples.add" x y

您可以通过将服务器包装在“对象”中并将其作为第一个参数传递给所有“方法”来模拟Haskell中的OOP方法:

module MyServer (
    Server, -- don't expose constructor
    newServer,
    add,
) where

data Server = Server String

newServer :: String -> IO Server
newServer = return . Server

add :: Server -> Int -> Int -> IO Int
add (Server url) = remote url "examples.add"

您每次拨打电话时仍然必须通过服务器,但现在您可以更改服务器的表示(例如,使其成为持久连接的句柄)。

此外,您可以使用reader monad来隐式传递服务器:

class MonadServer m where
    withServer :: (Server -> m a) -> m a

instance MonadServer (ReaderT Server m) where
    withServer f = ReaderT (\server -> runReaderT (f server) server)

add :: (MonadIO m, MonadServer m) => Int -> Int -> m Int
add x y = withServer (\(Server url) -> liftIO $ remote url "examples.add" x y)

通过使MonadServer成为类型类,可以扩展您使用的任何读者monad以支持隐式Server参数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM