显示类型A - > A.

Car*_*mey 6 haskell typeclass

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

instance Show (Fun (A -> A) String) where
  show (Fun f s) = s
Run Code Online (Sandbox Code Playgroud)

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

/home/kmels/tmp/show-abs.hs:4:16:
    Not in scope: type constructor or class `Fun'
Run Code Online (Sandbox Code Playgroud)

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

data FunWithAttribute = FA (A -> A) String 
Run Code Online (Sandbox Code Playgroud)

添加data A = Num Int | Fun FunWithAttribute和写入instance Show FunWithAttribute.附加数据类型是否可以避免?

C. *_*ann 11

实例是为整个类型定义的,而不是单独的构造函数,这就是为什么它抱怨Fun不是一个类型.

我假设你的总体目标是拥有一个Show实例A,这个实例无法派生,因为函数不能(通常)有一个Show实例.你有两个选择:

Show直接编写自己的实例:

就是这样的:

instance Show A where
    show (Num n) = "Num " ++ show n
    show (Fun _ s) = s
Run Code Online (Sandbox Code Playgroud)

在许多情况下,这是最有意义的.但有时它的推导更好Show,特别是在复杂的递归类型中,其中只有一种情况不能自动Show生成.

使A派生:

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

instance Show (A -> A) where
    show _ = "(A -> A)"
Run Code Online (Sandbox Code Playgroud)

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

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

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

data ShowAs a = ShowAs a String

instance Show (ShowAs a) where
    show (ShowAs _ s) = s
Run Code Online (Sandbox Code Playgroud)

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


wor*_*shi 5

也许我没有按照你的要求去做.但是上面的代码可以像这样编写以便编译:

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

instance Show A where
  show (Fun f s) = s
  show (Num i) = show i
Run Code Online (Sandbox Code Playgroud)

一些解释

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

此外,deriving除非每个构造函数的每个参数在这种情况下成为其成员,否则不能使用Show.现在,你的例子有点特别,因为它想要Show (A -> A).如何展示一个功能在其他回复中有所解释,尽管我认为没有详尽的方法.其他示例实际上只是"显示"类型或某个占位符.