【问题标题】:Why can't the type of take be changed to use any Integral?为什么不能将 take 的类型更改为使用任何 Integral?
【发布时间】:2013-06-23 16:33:24
【问题描述】:
take :: Int -> [a] -> [a]
genericTake :: Integral i => i -> [a] -> [a]

我读到take的不方便类型是由于历史原因,更改它可能会导致某些代码中断。

但是我不能在任何地方都用genericTake 替换take 而不会破坏任何东西吗?有什么问题?

【问题讨论】:

  • 我猜可能会出现类型派生基于take 类型的情况——genericTake 会出现“无法派生”的情况。
  • 请注意,除了在晦涩难懂的情况下(并且可能更实际相关)代码损坏之外,在很多情况下将 take 替换为 genericTake 会导致性能下降(因为类型默认将现在导致在未指定 :: Int 时使用 Integer)。

标签: haskell


【解决方案1】:

破案

genericTake :: Integral i => i -> [a] -> [a]
genericTake n xs = take (fromIntegral n) xs

class Foo a where
   bar :: a -> String

instance Foo Int where
   bar _ = "int" 

foo :: String -> [a] -> [a]
foo ns xs = let y = read ns
                z = bar y
            in take y xs

genericTake 会中断。

No instance for (Foo i0) arising from a use of `bar'
    The type variable `i0' is ambiguous

这是一个复杂的例子,但你可以理解发生在 take 的第一个参数上的一些类型推断,假设它是 Int,现在当你将类型更改为 Integral i => i 时,可能会出现如上所述的一些问题。

【讨论】:

  • +1 这对于类型实例来说真的很痛苦,我希望它得到修复。
  • @jpaugh 你有什么建议是修复?我不确定它是否可以修复。
  • 这个没试过,但是这不会用扩展的默认规则编译吗?
  • @PhilipJF 这是关于什么代码会在不更改任何内容的情况下中断。因此,如果现有库中存在这样的代码,则更改 take 类型将破坏该代码。当然,你可以做很多事情来解决这个问题。
  • @PhilipJF 在这种情况下,扩展类型默认规则不会改变任何东西。标准的默认规则已经在这里应用了,但是由于相关的默认值是Integer,而不是Int,它们在这里根本没有帮助。扩展规则仅在更多情况下引入默认值 - 它们不会导致此处选择 Int 作为默认值。
猜你喜欢
  • 1970-01-01
  • 2014-07-20
  • 2020-06-06
  • 2014-01-15
  • 1970-01-01
  • 2021-12-16
  • 2021-10-08
  • 2018-11-04
  • 2012-12-30
相关资源
最近更新 更多