假设我有一些通用功能

genericFunc :: a -> b
genericFunc x = doSomeHardWork

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

genericFunc :: ParticularType -> b
genericFunc x = doSomeEasyWork

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

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

===============>>#1 票数:8 已采纳

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

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

===============>>#2 票数:2

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

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

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

  ask by Dan Burton translate from so

未解决问题?本站智能推荐:

1回复

动态对象:获取子泛型类型并将其提供给另一种方法

我有一个方法,它基本上接收一个dynamic对象。 这是由于动态调度造成的,这不是讨论为什么在这里使用dynamic输入的重点。 我知道此dynamic对象表示ASpecialClass<T>类型,其中T在编译时未知。 有没有办法提取T类型并将其提供给另一种方法? 喜
2回复

动态调度,智能构造函数,Template Haskell也许?

我正在查看HaskellWiki>现有类型#动态调度机制 。 我在想,模板Haskell中应该有一种方法可以参与这一部分: 并自动得出这一部分: 这是在模板Haskell中完成的吗? 可以在TH中完成吗? 是否可以在普通的旧Haskell中完成类似的操作而不必手工
2回复

动态调用extjs类中的函数

我有一个ExtJs类,看起来像这样: 现在,我得到一个字符串=> str ,其中包含我需要运行的方法名称。 我需要在str中的字符串指定的 RuleExecutor中调用方法 该方法已正确调用 ,但未传递参数。 像这样:
1回复

如何在Rust中实现执行动态调度的泛型函数?

在我正在研究的项目中,存在此对象: OurObject是以某种方式“打包”的东西的容器。 每个可以打包的东西都具有各种特征。 我们以重复的代码结尾,例如: 我想将match代码分解为一个函数,以便我们可以调度任意特征。 但是,我遇到了问题... T应该代表
2回复

将scala代码推广到函数中

所以我最近不小心写了一个关于Scala问题的Haskell答案。 对Haskell比较熟悉,解决方案很容易对我来说: 然后有人提醒我这是一个Scala问题。 我开始将我的代码转换为Scala,经过多次努力后我决定: 但我不能为我的生活让Scala类型系统屈服于我的意愿并将其概
1回复

隐藏和接收通用T对象

给出了以下Rust代码: Wrapper<T>存储通用Vec ,详细地是列存储中的数据列。 相应的实现返回Vec或特定元素作为参考。 Inter<T>和GetInter特性的想法是隐藏通用T对象,该对象来自包装器的Vec<T>通用数据类型。
2回复

GHC是否使用存在类型的动态调度?

下面的代码是否使用动态分派,因为它在C ++或Java中被理解? 据我所知,在最后一行,编译器不可能在编译时知道调用(==)的实现,但代码编译并产生正确的结果。 有人可以解释一下,这背后有什么样的实现(比如vptr)?
2回复

Haskell和一般类型

我是Haskell的新手,我想了解一般类型的工作原理。 什么应该是一种“系统的”思维方式来获得表达的类型? 举个例子,如果我们有: 我想到的方式,只是使用直觉,但它总是不起作用。 在这种情况下,我会说: 我很确定这应该是正确的,但有时它更难以这种方式去思考似乎不
1回复

通用函数中的Haskell类型构造函数

我在Haskell Lava HDL系统中四处搜寻,并停留在了解http://hackage.haskell.org/package/chalmers-lava2000-1.6.1/docs/src/Lava-Vhdl.html#writeVhdl 有人可以告诉我writeVhdl函数(v
8回复

编写一个通用函数,其中包含两种类型的参数

这是对此问题的后续问题。 我想我在Haskell中有点误解了什么类型,所以希望这是一个更好的问题表达方式: 我想要一个可以用两个参数调用的函数。 这些参数必须是不同的类型。 例如,一个是字符串,另一个是整数。 考虑这个应用: 编写具体的实现不是问题,但是,对我来说,给这