假设函数foo
,bar
noo
是我程序中的基础知识。此外,这些功能可以在不同的场景(foo1, bar1
,foo2, bar2
等)中以不同的方式实现,但foo1
和foo2
仍有相同的输入和输出类型。根据某些输入或配置,程序在某些场景中使用foo1, bar1
,而在另一个场景中使用foo2, bar2
。
我可以如上所述定义它们,将后缀(1,2,3 ..)附加到foo, bar, noo
。然而,这并不漂亮,因为后缀可能很长;它也不允许foo1
与bar1
(与bar2
)进行特殊绑定。
另一种方法是将每个场景视为单独的Module
。现在每个案例的foo, bar, noo
很好地保持在一起,避免了丑陋的后缀。但是,当每个Module
有一个文件时,这会引入许多文件。这种方法的另一个缺点是这些Modules
完全分开,即使它们确实共享一些相似性(例如三个函数)。
typeclass
解决方案会受到赞赏,但我不介意,因为不同场景的不同foo
具有相同的输入和输出。
我想知道是否有任何Haskell问题的最佳实践,以避免上述这些方法的缺点。
foo1 :: Double -> Double
bar1 :: Int -> Int
noo1 :: [Int] -> [Int]
foo2 :: Double -> Double
bar2 :: Int -> Int
noo2 :: [Int] -> [Int]
...
foo9 :: Double -> Double
bar9 :: Int -> Int
noo9 :: [Int] -> [Int]
编辑:我想这对于解释如何通过Java Interface
来解决这个问题很重要(对Java interface
的一些不错但概念层面的讨论可以在this post和here找到Haskell typeclass
。)Java interface and class
在很多情况下都很复杂,但这里的重载实际上很简洁。
interface Scenario {
double foo(double d);
int bar(int i);
Array<int> noo(Array<int> a);
}
class UseScenario {
void use(Scenario ss) {
ss.foo(...);
ss.bar(...);
ss.noo(...);
}
}
class S1 implements Scenario {
double foo(double d) {...};
int bar(int i) {...};
Array<int> noo(Array<int> a) {...};
}
class S2 implements Scenario {
double foo(double d) {...};
int bar(int i) {...};
Array<int> noo(Array<int> a) {...};
}
答案 0 :(得分:6)
一个好方法是将所有函数放入单个数据类型中。然后针对每种不同的策略使用该类型的不同值。最后,选择默认策略,并将实际功能链接到默认策略(为了便于使用)。例如:
module MyModule where
data Strategy = Strategy {
fooWithStrategy :: Double -> Double
, barWithStrategy :: Int -> Int
, nooWithStrategy :: [Int] -> [Int]
}
defaultStrategy :: Strategy
defaultStrategy = Strategy {
fooWithStrategy = (*2)
, barWithStrategy = (+2)
, nooWithStrategy = id
}
foo :: Double -> Double
foo = fooWithStrategy defaultStrategy
bar :: Int -> Int
bar = barWithStrategy defaultStrategy
noo :: [Int] -> [Int]
noo = nooWithStrategy defaultStrategy
tripleStrategy :: Strategy
tripleStrategy = Strategy {
fooWithStrategy = (*3)
, barWithStrategy = (*3)
, nooWithStrategy = \x -> x ++ x ++ x
}
customAddStrategy :: Int -> Strategy
customAddStrategy n = Strategy {
fooWithStrategy = (+ (fromIntegral n))
, barWithStrategy = (+ n)
, nooWithStrategy = (n :)
}
这允许许多有用的功能:
customAddStrategy
)。您还可以混合和匹配策略,例如newStrat = defaultStrategy { nooWithStrategy = nooWithStrategy tripleStrategy, fooWithStrategy = (*4) }
foo
,bar
和noo
)可供新手使用的用户使用