如何在没有注释的情况下明确地制作这个伪鸭式类型的例子

How to make this example of pseudo-ducktyping type unambiguously without annotations

我想使用 MultiParamTypeClasses 在 Haskell 中演示静态可验证鸭子输入的想法,但我无法避免类型歧义。

代码如下:

{-# LANGUAGE MultiParamTypeClasses #-}

class HasBar a b where
    bar :: b -> a 

data Foo = Foo { barBool :: Bool } deriving (Show)

instance HasBar Bool Foo where
    bar = barBool

data Bazz = Bazz { barInt :: Int } deriving (Show)

instance HasBar Int Bazz where
    bar = barInt

当我将它加载到 GHCi 并尝试执行 bar (Foo True)bar (Bazz 5) 时,我收到 Non type-variable argument 错误,它提示 FlexibleContexts,这只是将错误更改为歧义错误。现在做 False || bar (Foo True) 之类的事情就可以了。但这似乎并不需要它,因为 Foo 只是 returns a Bool.

类型类的成员

这个问题似乎与以下可能性有关:

instance HasBar Int Foo where
    bar = const 5

这需要类型不明确。但是,如果只有一个实例,我不明白为什么会有任何问题阻止 Haskell 找出类型(我需要某种扩展吗)。如果我不能那样做,那么有没有 MultiParamTypeClasses 的替代方案,它只允许一个实例,并且允许这种伪鸭子打字类型的东西起作用?

问题是它不仅在寻找它看到的,而且在寻找它能知道的东西——你有可能制作一个也将是 HasBar Int Foo 的实例,因此它会抱怨

您可以使用 FunctionalDependencies or TypeFamilies

使用函数依赖

第一个扩展可能是这里的方法(您不必更改太多代码)。您基本上可以告诉 GHCi,您 class/constraint 中的类型 b 足以决定类型 a.

如果将其更改为:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}

class HasBar a b | b -> a where
    bar :: b -> a 

它会起作用(你只在 GHCi

中需要 FlexibleContexts
λ> :set -XFlexibleContexts
λ> bar (Foo True)
True

使用家庭类型

如果您感兴趣,这里是类型族和关联类型的同一件事:

{-# LANGUAGE TypeFamilies #-}

class HasBar a where
  type Bar a :: *
  bar :: a -> Bar a

data Foo = Foo { barBool :: Bool } deriving (Show)

instance HasBar Foo where
  type Bar Foo = Bool
  bar = barBool

data Bazz = Bazz { barInt :: Int } deriving (Show)

instance HasBar Bazz where
  type  Bar Bazz = Int
  bar = barInt

请注意,您不再需要 MultiParamTypeClasses