如何在Stack单库多可执行文件项目中编译时定义用户自定义类型
解决单库多可执行文件的类型定制问题
嘿,这个需求我之前也碰到过!用Stack搞单库多可执行文件架构,想让某个类型在不同可执行文件里有不同实现,其实用Haskell的类型系统就能轻松搞定,给你两种实用方案:
方案1:简单类型替换(适合仅类型不同、行为类似的场景)
如果你的库函数只依赖类型的通用特性(比如Show、Num),可以直接让库函数保持多态,然后在每个可执行文件里定义自己的类型别名。
第一步:改造库代码
把原来固定的Int别名换成多态函数,比如:
-- src/MyLib.hs -- 去掉原来的 type MyType = Int process :: Show a => a -> String process x = "处理结果:" ++ show x -- 要是有更复杂的数值计算,就加Num约束 calculate :: Num a => a -> a calculate x = x * 10
第二步:在每个可执行文件里定制类型
比如第一个可执行文件用String:
-- app/demo-string/Main.hs import MyLib (process, calculate) -- 自定义类型别名 type MyType = String main :: IO () main = do putStrLn $ process ("Hello Haskell" :: MyType)
第二个可执行文件用Double:
-- app/demo-double/Main.hs import MyLib (process, calculate) type MyType = Double main :: IO () main = do putStrLn $ process (3.14 :: MyType) print $ calculate (2.5 :: MyType)
方案2:类型类定制(适合不同类型有不同行为的场景)
如果每个类型需要完全不同的逻辑,用类型类(Typeclass) 来抽象行为,让每个可执行文件提供自己的类型实例。
第一步:库中定义类型类
把业务逻辑抽象成类型类,代替固定的类型别名:
-- src/MyLib.hs class MyProcessable a where process :: a -> String calculate :: a -> a -- 可以定义多个需要定制的方法 -- 可选:给默认类型(比如原来的Int)加实例,作为 fallback instance MyProcessable Int where process x = "处理整数:" ++ show x calculate x = x * 20
第二步:可执行文件中实现自定义类型与实例
比如第一个可执行文件用自定义的字符串类型:
-- app/demo-custom-string/Main.hs import MyLib (MyProcessable(..)) -- 定义自己的类型 newtype MyCustomString = MyCustomString String -- 实现类型类 instance MyProcessable MyCustomString where process (MyCustomString s) = "处理自定义字符串:" ++ reverse s calculate (MyCustomString s) = MyCustomString (s ++ s) main :: IO () main = do putStrLn $ process (MyCustomString "Stack Rocks") let result = calculate (MyCustomString "Repeat") print result
第二个可执行文件用自定义的布尔类型:
-- app/demo-custom-bool/Main.hs import MyLib (MyProcessable(..)) newtype MyCustomBool = MyCustomBool Bool instance MyProcessable MyCustomBool where process (MyCustomBool b) = "处理布尔值:" ++ if b then "是" else "否" calculate (MyCustomBool b) = MyCustomBool (not b) main :: IO () main = do putStrLn $ process (MyCustomBool True) print $ calculate (MyCustomBool False)
最后:Stack配置多可执行文件
记得在你的package.yaml(或者stack.yaml)里配置好所有可执行文件,比如:
library: source-dirs: src executables: demo-string: main: Main.hs source-dirs: app/demo-string dependencies: - your-library-name demo-double: main: Main.hs source-dirs: app/demo-double dependencies: - your-library-name demo-custom-string: main: Main.hs source-dirs: app/demo-custom-string dependencies: - your-library-name
这样编译的时候,Stack会为每个可执行文件单独构建,各自用自己的定制类型~
内容的提问来源于stack exchange,提问作者lhcopetti
相关产品推荐
相关产品推荐

