繁体   English   中英

根据类型为通用函数提供不同的函数体

[英]Provide a different function body for a generic function based on type

假设我有一些通用功能

genericFunc :: a -> b
genericFunc x = doSomeHardWork

但是对于特定类型,有一种更有效的方式可以完成genericFunc

genericFunc :: ParticularType -> b
genericFunc x = doSomeEasyWork

将这两个函数体组合到同一个genericFunc的最佳方法是什么,这样当在ParticularType使用时,它会doSomeEasyWork ,但是当在其他类型上使用时,它会doSomeHardWork 我特别排除了使用不同名称或不同模块的选项。

我相信这可以通过类型类来完成,但我对使用语言编译指示的解决方案更感兴趣。 我有一个模糊的暗示,这可以用语言编译,但我不知道如何。 如果您比较和对比这些方法和/或任何其他可能的方法,奖励积分。

这可以通过在类定义中定义通用方法并在实例中覆盖它来使用类型类来完成。 将始终使用重写的函数。

class ContainsInt c where
  toList :: c -> [Int]

  -- generic function
  elem :: Int -> c -> Bool
  elem n x = Prelude.elem n (toList x)

instance ContainsInt () where
  toList _ = []

  -- Override the generic function for type ()
  elem _ _ = False

GHC支持的另一种方法是使用重写规则。 重写规则告诉GHC尽可能用另一个表达式替换另一个表达式。 如果替换是错误的,则不会执行,因此您可以使用它来替换专用版本的功能。 重写规则由{-# RULES #-} pragma给出。

class ContainsInt c where
  toList :: c -> [Int]

elem :: ContainsInt c => Int -> c -> Bool
elem n x = Prelude.elem n (toList x)

-- Replace 'elem' by 'elemUnit' if it has the same type
{-# RULES "elem()" forall. elem = elemUnit #-}

elemUnit :: Int -> () -> Bool
elemUnit _ _ = False

重写规则由编译器自行决定,因此在任何给定情况下都可以调用或不调用专用函数。 例如,重写可能取决于编译器是否决定内联函数:

foo :: ContainsInt c -> Int -> [c] -> [Bool]
-- Must use the generic function
foo n cs = map (elem n) cs

useFoo :: Int -> [()] -> [Bool]
-- If 'foo' is inlined and 'elem' is not inlined, then this function will contain a rewritable call to 'elem'.
-- Otherwise rewriting cannot happen.
useFoo n cs = foo n cs

使用GHC,您可以使用RULES编译指示

{-# RULES "genericFunc/easy" genericFunc = doSomeEasyWork #-}

这将在类型匹配时应用重写规则,否则将使用泛型实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM