有什么方法可以使用 class 的名称作为常用数据类型的名称吗?

Is there any way of using name of class as a name of usual data type?

嗯,我有两个结构(两个 ADT)CashierPorter,它们有共同的 属性 salary。它是通过实现 class Worker.

实现的
type Money = Int
type Kg = Int

class Worker a where
    salary :: a -> Money

data Cashier = C { salaryC :: Money 
                 , polite :: Bool
                 }

instance Worker Cashier where
    salary = salaryC

data Porter = P { salaryP :: Money
                , liftingForce :: Kg
                }

instance Worker Porter where
    salary = salaryP

共同的界面意味着共同的行动。这使我能够不编写使用给定 ADT 的公共 属性 的任何函数的两种不同变体。

例如:

hasSalary :: (Worker a) => a -> Bool
hasSalary x = (salary x) > 0

但是当我尝试声明另一种类型时,例如 data Stuff = S [Worker] 编译器不允许我这样做。

当然也行不通 type Stuff = [(Worker a) => a](Worker a) => type Stuff = [a]

是的,有数据类型构造函数:

data (Worker a) => Stuff a = S [a]

甚至 GADT 的版本:

data Stuff a where
    S :: Worker a => [a] -> Stuff [a]

但这不是我真正想要的。因为每次我使用 Stuff 时,Stuff CashierStuff Porter 之间都会有区别。

因此,是否有使用 class' 名称 Worker 作为结构中字段类型的任何变体,就像它是通常的数据类型(Int 对于例如)?

在阅读 this piece of mandatory reading 之前,请勿使用此答案中的任何内容。


如果我没看错(或者,猜到真的,不太清楚),你要的是异构集合:一个可以包含 Cashiers 和 Porters 的任意组合的列表。毕竟 List<Worker> 在 Java.

这样的语言中就是这样

为此,

type Stuff = [(Worker a) => a]

是你尝试过的有意义的东西:a 必须只出现在列表条目中,而不是在整体数据类型中(因为那样它们就被限制为相同的类型)。

事实上,如果 Haskell 有一个 存在量词 :

,那么尝试 成功
type Stuff = [∃ a . Worker a => a]

Haskell 没有那个,但是可以将存在性包装在 GADT 中:

data AWorker where
  AWorker :: Worker a => a -> AWorker

type Stuff = [AWorker]