如何在没有注释的情况下明确地制作这个伪鸭式类型的例子
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
我想使用 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