Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 多个模块的通用接口_Haskell - Fatal编程技术网

Haskell 多个模块的通用接口

Haskell 多个模块的通用接口,haskell,Haskell,我想让用户能够首先使用import-DryRun运行程序,然后使用import-Do运行程序,如果他认为一切都是正确的。 因此,有一个模块进行实际工作: doThis ∷ SomeStack () doThis = actuallyDoThis ... doThat ∷ SomeStack () doThat = actuallyDoThat 和一个供害羞用户使用的模块: doThis ∷ SomeStack () doThis = liftIO $ putStrLn "DoThis" ...

我想让用户能够首先使用
import-DryRun
运行程序,然后使用
import-Do
运行程序,如果他认为一切都是正确的。
因此,有一个模块进行实际工作:

doThis ∷ SomeStack ()
doThis = actuallyDoThis
...
doThat ∷ SomeStack ()
doThat = actuallyDoThat
和一个供害羞用户使用的模块:

doThis ∷ SomeStack ()
doThis = liftIO $ putStrLn "DoThis"
...
doThat ∷ SomeStack ()
doThat = liftIO $ puStrlLn "DoThat"
问题是我无法确定
Do
DryRun
中的接口是否相同(编译器无法帮助),并且在开发过程中很难维护这种混乱状态。

有没有解决这类问题的常用习惯用法?

您可以具体化有问题的模块。也就是说,在基本模块中定义一个数据类型:

module Base where
data MyModule = MyModule {
    doThis_ :: SomeStack (),
    doThat_ :: SomeStack ()
}
使用每个模块需要导出的内容(下划线的原因很快就会显现出来)

然后,您可以在每个模块中定义此类型的值,例如:

module DryRun(moduleImpl) where
import Base
moduleImpl :: MyModule
moduleImpl = MyModule doThis doThat
-- doThis and doThat defined as above, with liftIO . putStrLn

module Do(moduleImpl) where
import Base
moduleImpl :: MyModule
moduleImpl = MyModule doThis doThat
-- doThis and doThat defined as above, where the real work gets done
我不会使用记录语法构造
MyModule
值,以确保在大多数情况下,如果
MyModule
发生更改,类型检查器将开始抱怨

在客户端模块中,您可以执行以下操作

module Client where
import DryRun
-- import Do -- uncomment as needed

doThis = doThis_ moduleImpl
doThat = doThat_ moduleImpl

-- do whatever you want here
现在您知道两个模块导出相同的操作。这无疑是乏味和笨拙的,但由于Haskell没有一流的模块,因此您必须始终克服模块系统的限制。好的是,只需编写一次基本模块和客户机模块,就可以开始定义对
MyModule
值进行操作的组合器。例如

doNothing = MyModule (return ()) (return ())
addTracing impl = MyModule ((liftIO $ putStrLn "DoThis") >> doThis_ impl) 
                           ((liftIO $ putStrLn "DoThat") >> doThat_ impl)

如果我没有弄错的话,将允许您用添加跟踪操作来替换
DryRun
模块实现。

是否将同一类型类的两个实现实例作为选项?@GregBacon,两个monad堆栈的副本当然是一个选项,但如果有不涉及复制的内容,我会使用它。在两个模块上运行haddock并比较生成的文档。
SomeStack
是否也会因是否包含
Do
DryRun
模块而有所不同,或者这两个模块的类型相同?