在一个项目中,我使用一个包含全局(初始化后常量)东西的模块,我在项目的其余部分使用。我选择将它们放入一个模块中,以避免传递很多参数。问题是这个模块必须在运行时使用程序执行的参数进行初始化。
这如何在函数范式中完成,例如在像Haskell这样的语言中?
编辑:
更准确地说,我用命令式语言 (Ada) 编写我的项目,这就是为什么我可以使用一个模块,其中包含在运行时初始化的变量,然后用作全局常量(带有内联 getter)。但是,由于对函数式编程感兴趣,我想知道如何在这种范式中获得相同的结果;我的意思是在代码的其余部分(使用全局常量)上都有光签名,模块数据本地化在内存的数据部分,甚至能够单独初始化模块的不同"常量"等。
如果程序的行为取决于命令行上使用的参数,则根本无法隐藏这一事实 - 它必须出现在程序组件的类型中。最简单的方法是写
data Options = {- ... -}
doMyProgram :: Options -> IO ()
myModule'sConstantA :: Options -> A
myModule'sConstantB :: Options -> B
将Options
作为依赖于它的任何操作或值的参数。花哨的设计通常还为程序定义一个自定义 monad M
,其中包含一个 MonadReader Options M
实例,以减少类型签名的大小。
严格来说,这并非不可能,可能不应该这样做。
import System.Environment
import System.IO.Unsafe
firstArg :: String
firstArg = head $ unsafePerformIO getArgs
{-# NOINLINE firstArg #-}
main = putStrLn firstArg
请注意"不安全"一词在这六行代码段中出现的次数。
它既肮脏又恶心,但 IMO,这种范式有一些有效的用例,全局常量初始化就是其中之一。例如,我用它来加载游戏中的关卡文件。