Dan*_*ton 5 generics haskell function dynamic-dispatch
假设我有一些通用功能
genericFunc :: a -> b
genericFunc x = doSomeHardWork
Run Code Online (Sandbox Code Playgroud)
但对于特定类型,可以采用更有效的方式genericFunc.
genericFunc :: ParticularType -> b
genericFunc x = doSomeEasyWork
Run Code Online (Sandbox Code Playgroud)
将这两个函数体组合成相同的最佳方法是什么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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
重写规则由编译器自行决定,因此在任何给定情况下都可以调用或不调用专用函数.例如,重写可能取决于编译器是否决定内联函数:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
148 次 |
| 最近记录: |