Haskell 嵌套的类型不明的方法

Haskell 嵌套的类型不明的方法,haskell,Haskell,说我有课 class T where tag1 :: String tag2 :: String 启用模糊类型后,我可以在实例中指定它们中的每一个: instance T A where tag1 = "tag1" tag2 = "tag2" 如果我想将tag2附加到tag1中,我可以定义 instance T A where tag1 = "tag1" tag2 = tag1 @A ++ " suffix" 这非常有效,但是如果我希望ta

说我有课

class T where
    tag1 :: String
    tag2 :: String
启用模糊类型后,我可以在实例中指定它们中的每一个:

instance T A where
    tag1 = "tag1"
    tag2 = "tag2"
如果我想将
tag2
附加到
tag1
中,我可以定义

instance T A where 
    tag1 = "tag1"
    tag2 = tag1 @A ++ " suffix"
这非常有效,但是如果我希望
tag2
总是在每个
tag1
中附加
后缀
,我似乎必须为每个实例指定不明确的调用

我理解这样做的必要性,因为来自任何实例的
tag1
都适用于每个调用。然而,haskell中是否有任何技巧让我只指定一次

差不多

tag2 :: T a => String
tag2 = tag1 @a ++ " suffix"

是的,您可以完全这样做-
tag1@a
,但是您需要做两个修改:启用
ScopedTypeVariables
并为所有
添加一个显式的
,如下所示:

tag2 :: forall a. T a => String 
tag2 = tag1 @a ++ " suffix"
class T a where
    tag1 :: String

    tag2 :: String
    tag2 = tag1 @a ++ " suffix"
显式的
forall
为类型变量
a
创建了一个作用域,使得它可以在
tag2
的整个主体中访问。没有它(即根据标准Haskell 2010规则),类型变量的作用域仅限于类型签名,并且在主体中无法访问

如果希望将
tag2
作为类方法,而不是独立函数,则可以为其添加如下默认实现:

tag2 :: forall a. T a => String 
tag2 = tag1 @a ++ " suffix"
class T a where
    tag1 :: String

    tag2 :: String
    tag2 = tag1 @a ++ " suffix"

在这种情况下,不需要为所有
提供显式的
。相反,类型变量的作用域将是整个类实例。但是您仍然需要
ScopedTypeVariables
,否则将根本没有作用域。

您的代码当前没有编译,因为类型类没有类型参数,所以我将假设您的代码实际上是(假设启用了
AllowAmbiguousTypes

现在,您可以为
tag2
提供默认实现:

class T a where
    tag1 :: String
    tag2 :: String
    tag2 = "tag2"
但这不符合向
tag1
添加后缀的要求
我们可以尝试这样做(假设启用了
TypeApplications
):

现在,这将不会编译,编译错误将被忽略

error: Not in scope: type variable `a'
正确地说,类型
a
没有在任何地方定义。但是,我们希望在类的开头引用
a
,为此我们需要语言扩展,代码将编译,您将得到预期的结果(我建议阅读链接文档)

下面是一个完整的程序,演示了该用法:

{-# LANGUAGE TypeApplications, AllowAmbiguousTypes, ScopedTypeVariables #-}

class T a where
  tag1 :: String
  tag2 :: String
  tag2 = tag1 @a ++ " suffix"

data A = A
data B = B

instance T A where
  tag1 = "tagA"

instance T B where
  tag1 = "tagB"
  tag2 = "tagB overriden"

main = do
  putStrLn $ tag1 @A
  putStrLn $ tag2 @A
  putStrLn $ tag1 @B
  putStrLn $ tag2 @B
输出为:

> ./foo
tagA
tagA suffix
tagB
tagB overriden

目前,您的代码没有编译,因为该类没有参数。我在键入时确实犯了一个错误。两个答案都很好,但我会接受你的答案,因为我相信你是第一个回答的。我没有意识到语言标志