在Haskell中推广函数

时间:2016-06-01 03:14:25

标签: haskell functional-programming

这两个功能几乎相同:

<img onclick="imageChange(this)" style="width: 200px; cursor: pointer;" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png">

<script>
window.imageChange = function(image) {
        if (image.style.width === "200px") {
        image.style.width = "100px";
    } else {
        image.style.width = "200px";
    }
}
</script>

唯一的区别在于 where 子句中定义的函数。

以下限制适用:

  • dig :: MappingClassifierM FileSummary IO Partitioner -> Conduit (Cluster Partitioner FileSummary) IO (Cluster Partitioner FileSummary) dig classifier = await >>= \case Nothing -> return () Just ( Cluster clusterKey clusterValue ) -> do categories <- liftIO $ classify classifier clusterValue if (length clusterValue == length categories) then do yield $ Cluster clusterKey clusterValue dig classifier else do mapM_ (yield . cluster) categories dig classifier where cluster (key, val) = Cluster (key : clusterKey) val classify = classifyM dig' :: BinaryClassifierM FileSummary IO -> Conduit (Cluster Partitioner FileSummary) IO (Cluster Partitioner FileSummary) dig' classifier = await >>= \case Nothing -> return () Just ( Cluster clusterKey clusterValue ) -> do categories <- liftIO $ classify classifier clusterValue if (length clusterValue == length categories) then do yield $ Cluster clusterKey clusterValue dig' classifier else do mapM_ (yield . cluster) categories dig' classifier where cluster = Cluster (Content : clusterKey) classify = classifyBinary 函数取决于作为第一个参数传递的分类器的“类型”。
  • classify函数取决于分类器的实际实现。

我想概括这两个函数,以便创建一个处理两个实现的单个函数,以避免重复。

我不知道我是否朝着正确的方向前进。基于我迄今为止对Haskell的有限知识,我认为我必须创建一个类“Classifier”,BinaryClassifier和MappingClassifierM将成为其实例,但是当我尝试实现它时,我面临着几个编译错误

所以,我的问题是:经验丰富的Haskell程序员如何概括这两个函数以避免重复?

对于其他上下文,下面是我试图概括的两种不同情况的相关类型签名:

cluster

2 个答案:

答案 0 :(得分:1)

我的方法是让编译器为我做大部分的思考。首先,我使用了公共代码并使其成为自己的函数

dig'' classifier =
  await >>= \case
    Nothing -> return ()
    Just ( Cluster clusterKey clusterValue ) -> do
      categories <- liftIO $ classify classifier clusterValue
      if (length clusterValue == length categories)
        then do
          yield $ Cluster clusterKey clusterValue
          dig'' classifier
        else do
          mapM_ (yield . cluster) categories
          dig'' classifier

这会导致一些问题。首先,编译器抱怨clusterclassify未定义,因此我们需要将它们作为参数添加到函数中。您还会注意到分类器从不在分类函数之外使用,因此我们将它们组合成一个值。此外,由于我们已经更改了函数的参数,我们的递归调用会发生变化,因此我们需要处理这些调用。

dig'' cluster =
  await >>= \case
    Nothing -> return ()
    Just ( Cluster clusterKey clusterValue ) -> do
      categories <- liftIO $ classify clusterValue
      if (length clusterValue == length categories)
        then do
          yield $ Cluster clusterKey clusterValue
          dig'' cluster classify
        else do
          mapM_ (yield . cluster) categories
          dig'' cluster classify

这里我注意到where子句中的cluster需要clusterKey,因此它需要以某种方式作为参数传递。

dig'' cluster =
  await >>= \case
    Nothing -> return ()
    Just ( Cluster clusterKey clusterValue ) -> do
      categories <- liftIO $ classify clusterValue
      if (length clusterValue == length categories)
        then do
          yield $ Cluster clusterKey clusterValue
          dig'' cluster classify
        else do
          mapM_ (yield . cluster clusterKey) categories
          dig'' cluster classify

最后,使用类型孔让ghc为我找出数据类型。

dig'' :: _
dig'' cluster =
  await >>= \case
    Nothing -> return ()
    Just ( Cluster clusterKey clusterValue ) -> do
      categories <- liftIO $ classify clusterValue
      if (length clusterValue == length categories)
        then do
          yield $ Cluster clusterKey clusterValue
          dig'' cluster classify
        else do
          mapM_ (yield . cluster clusterKey) categories
          dig'' cluster classify

我的值为

(Foldable t, MonadIO m) =>
 ([a] -> a1 -> Cluster a b)
 -> ([b] -> IO (t a1)) -> Conduit (Cluster a b) m (Cluster a b)

但是您的结果可能会有所不同,因为我主要编写了所有数据类型。例如,我怀疑代码的[a][b]会有所不同。

现在,回到原来的功能。在这里,我们的优势在于我们已经知道了结果的类型。

dig :: MappingClassifierM FileSummary IO Partitioner -> Conduit (Cluster Partitioner FileSummary) IO (Cluster Partitioner FileSummary)
dig classifier = dig'' ????

现在我们只需要dig''的两个参数。第一个参数只是填入cluster定义,所以我们得到

(\clusterKey (key, val) -> Cluster (key : clusterKey) val)

第二个参数是classify,我们在分类器中滚动,所以它很简单     (classifyM分类器)

因此,最终的定义是

dig :: MappingClassifierM FileSummary IO Partitioner -> Conduit (Cluster Partitioner FileSummary) IO (Cluster Partitioner FileSummary)
dig classifier = dig'' (\clusterKey (key, val) -> Cluster (key : clusterKey) val) (classifyM classifier)

同样,您也可以找到

dig' :: BinaryClassifierM FileSummary IO -> Conduit (Cluster Partitioner FileSummary) IO (Cluster Partitioner FileSummary)
dig' classifier = dig'' (\clusterKey -> Cluster (Content : clusterKey)) (classifyBinary classifier)

答案 1 :(得分:1)

我能够使用允许某些语言扩展的类找到替代解决方案:

N