4

说功能foobar noo是我程序的基础。此外,这些功能可以在不同的场景foo1, bar1foo2, bar2等)中以不同的方式实现,但仍然具有相同的输入foo1foo2输出类型。根据一些输入或配置,程序foo1, bar1在某些场景下使用,而在另一种场景下foo2, bar2.

我可以像上面描述的那样定义它们,将后缀 (1,2,3..) 附加到foo, bar, noo. 但是,这并不漂亮,因为后缀可能很长;它也不允许特殊绑定foo1with bar1(vs. bar2)。

另一种方法是将每个场景视为单独的Module. 现在foo, bar, noo对于每个案例都很好地结合在一起,并且避免了丑陋的后缀。但是,当每个Module. 这种方法的另一个缺点是它们Modules是完全分开的,即使它们确实有一些相似之处(例如三个功能)。

一个typeclass解决方案将不胜感激,但我并没有想到,因为不同场景foo的不同s具有相同的输入和输出。

我想知道是否有针对该问题的 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可以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) {...};
}
4

1 回答 1

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 :)
  }

这允许许多有用的功能:

  1. 可定制的策略(例如customAddStrategy)。您还可以混合和匹配策略,例如newStrat = defaultStrategy { nooWithStrategy = nooWithStrategy tripleStrategy, fooWithStrategy = (*4) }
  2. 用户可以在运行时切换策略
  3. 默认值(即foo和)可用于库的新bar用户noo
  4. 您或其他用户可以使用更多策略轻松扩展。
于 2013-07-31T00:45:52.230 回答