【问题标题】:Insufficient definition of replicate重复定义不足
【发布时间】:2017-05-19 02:34:05
【问题描述】:

我有一个我认为相当棘手的问题。

标准前奏包含功能

replicate :: Int -> a -> [a]

以下似乎是一个合理的定义

replicate n x = take n [x,x,..]

但实际上还不够。为什么不呢?

我知道replicate函数定义为:

replicate        :: Int -> a -> [a]       
replicate n x    =  take n (repeat x)

repeat定义为:

repeat           :: a -> [a]  
repeat x         =  xs where xs = x:xs

定义是否不足(来自问题),因为它使用了无限列表?

【问题讨论】:

  • 您是否尝试编译建议的定义?编译器可能会告诉你为什么会有问题。 (顺便说一句,您应该复制问题中的文字,并避免使用图片。)

标签: haskell


【解决方案1】:

首先题中有个小语法错误,应该是:

replicate n x = take n [x,x..]
--                         ^ no comma

但我们不要挑剔。

现在,当您使用范围语法(即x..)时,x 应该是Enum 实例的类型。确实:

Prelude> :t \n x -> take n [x,x..]
\n x -> take n [x,x..] :: Enum a => Int -> a -> [a]

您可以争辩说x,x.. 只会生成x,但Haskell 编译器在编译时并不知道。

所以replicate(在问题中)中的类型太具体了:它暗示了一个类型约束 - Enum a - 实际上不是必要的。

另一方面,您自己的定义完全没问题。 Haskell 对无限列表没有问题,因为它使用惰性求值。此外,因为您将xsxs 定义为尾部,实际上构建了一个循环链表,它在内存使用方面也更好。

【讨论】:

  • 用于定义repeat 的循环链表并没有使replicate 的定义比以更直接的递归方式编写的定义更好。 replicate 本质上需要分配列表的全长(懒惰地)。 GHC 中实际发生的情况是这里使用的repeat 将与take 融合(通过重写规则),产生类似于手写replicate 的东西。
  • @dfeuer:它确实没有改进replicate 的定义,但我的观点是,它可以在某些情况下改进其他依赖repeat 的定义(从而改进@987654340 @ 本身)。例如,假设的 sumLess 是一个测试,如果总和较小则成功。由于您一直在使用相同的引用,因此如果 sumLess 正在遍历 repeat,则内存使用量不会增加。
  • 太棒了!非常感谢您的解释。
猜你喜欢
  • 2014-03-29
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 2013-03-14
  • 2014-03-05
  • 1970-01-01
相关资源
最近更新 更多