6
data A = Num Int
     | Fun (A -> A) String deriving Show

instance Show (Fun (A -> A) String) where
  show (Fun f s) = s

我想要一个函数的属性A -> A来打印它,因此有一个String类型参数Fun。当我将它加载到 ghci 中时,我得到

/home/kmels/tmp/show-abs.hs:4:16:
    Not in scope: type constructor or class `Fun'

我想这可以通过添加新的数据类型来实现

data FunWithAttribute = FA (A -> A) String 

添加data A = Num Int | Fun FunWithAttribute和编写instance Show FunWithAttribute. 额外的数据类型是可以避免的吗?

4

3 回答 3

11

实例是为整个类型定义的,而不是为单个构造函数定义的,这就是它抱怨Fun不是类型的原因。

我假设你的总体目标是有一个Show实例A,因为函数不能(通常)有一个Show实例,所以它不能被派生。你有几个选择:

直接编写您自己的Show实例:

也就是说,类似:

instance Show A where
    show (Num n) = "Num " ++ show n
    show (Fun _ s) = s

在许多情况下,这是最有意义的。但有时派生更好Show,特别是在复杂的递归类型上,其中只有一种情况不能自动Show-able。

使A可导:

您只能Show为包含本身具有Show实例的类型的类型派生。没有实例A -> A,因此推导不起作用。但是你可以写一个使用某种占位符的:

instance Show (A -> A) where
    show _ = "(A -> A)"

如果您愿意,甚至只是一个空字符串。

请注意,这需要语言FlexibleInstances扩展;它是最无害且最常用的扩展之一,受到多个 Haskell 实现的支持,而且它放松的限制(在我看来)一开始有点傻,所以没有理由避免它。

正如您在问题中提到的那样,另一种方法是使用包装器类型。你甚至可以使它更通用:

data ShowAs a = ShowAs a String

instance Show (ShowAs a) where
    show (ShowAs _ s) = s

...然后(ShowAs (A -> A))Fun构造函数中使用。这会迫使您在任何时候想要使用包装类型时进行额外的模式匹配,这使得它有点尴尬,但是它为您提供了很大的灵活性来“标记”东西应该如何显示,例如showId = id `ShowAs` "id"或类似的东西。

于 2013-02-12T19:22:36.357 回答
5

也许我没有遵循您的要求。但是上面的代码可以这样写以便编译:

data A = Num Int
     | Fun (A -> A) String 

instance Show A where
  show (Fun f s) = s
  show (Num i) = show i

一些解释

看起来您正在尝试为构造函数(Fun)编写一个显示实例。类实例是为整个数据类型编写的(可能有例外,不知道)。因此,您需要在每个构造函数上编写一个显示匹配作为实例的一部分。Num 和 Fun 都是数据类型 A 的构造函数。

此外,deriving除非每个构造函数的每个参数依次是Show. 现在,您的示例有点特别,因为它想要Show (A -> A). 如何显示功能在其他回复中有所解释,尽管我认为没有详尽的方法。其他示例实际上只是“显示”类型或某个占位符。

于 2013-02-12T19:17:43.053 回答
4

需要Show为数据类型定义实例(或任何类实例),而不是为类型构造函数定义。也就是说,您只需要

instance Show A where

显然,您正在尝试使用 获取此实例deriving,但这不起作用,因为 Haskell 不知道如何显示A->A。现在看来您甚至不想显示该功能,但deriving Show实例总是显示所有可用信息,因此您不能使用它。

解决您的问题的明显且最好的方法是 worldsayshi 的:根本不要使用deriving,而是自己定义一个适当的实例。或者,您可以定义一个伪实例A->A,然后使用派生:

{-# LANGUAGE FlexibleInstances      #-}

data A = Num Int | Fun (A->A) String   deriving(Show)

instance Show (A->A) where  show _ = ""

这就像

Prelude> Fun (const $ Num 3) "bla"
Fun  "bla"
于 2013-02-12T19:22:26.050 回答