类型命名空间阴影导致意外递归

时间:2013-09-24 03:11:19

标签: haskell

我无法为自定义数据类型定义Show的实例。

data Circle = Circle { x::Float, y::Float, r::Float }

instance Show Circle where 
show :: Circle -> String
show circle = concat $ 
  intersperse "," (map Prelude.show [x circle, y circle, r circle])

这一切都存在于一个名为Main.的模块中,对某些Circle Main.show circ调用circ会导致堆栈溢出异常。为什么GHC将Prelude.show的合格用法解释为对我在此处定义的函数的调用?

2 个答案:

答案 0 :(得分:7)

这是一个缩进问题。这是更正:

data Circle = Circle { x::Float, y::Float, r::Float }

instance Show Circle where 
  -- Illegal syntax
  -- show :: Circle -> String
  show circle = concat $ 
    intersperse "," (map show [x circle, y circle, r circle])

当您忘记缩进时,您将获得两个单独的声明:

instance Show Circle where { }

一个功能:

show :: Circle -> String

让我们忽略这个函数,因为它永远不会被调用。定义空类实例时,将获得函数的默认定义。这将传递Haskell类型检查器,因为show默认使用showsPrec,而showsPrec默认使用show。如果覆盖这两种方法中的一种或两种,则会得到Show的工作实例。如果不重写,则默认实现将相互递归并溢出堆栈。

关于Prelude.show

上述代码中只有一个show,即Prelude.show。实现类时,您没有实现名为“show”的 new 函数,但是您正在为泛型函数Prelude.show提供新的实现。

答案 1 :(得分:0)

我们还可以使用InstanceSigs扩展名来在实例中使用签名。 不要忘记在“where”中使用空格。

{-# LANGUAGE InstanceSigs #-}
data Circle = Circle { x::Float, y::Float, r::Float }

instance Show Circle where 
    show :: Circle -> String
    show circle = concat $ 
        intersperse "," (map show [x circle, y circle, r circle])