【问题标题】:Haskell type classes and instancesHaskell 类型的类和实例
【发布时间】:2019-08-21 15:56:22
【问题描述】:

为什么下面的代码需要Show 实例的约束和类型参数,但它们是否需要使Quad 成为Functor 的实例?

data Quad a = Quad a a a a 
instance (Show a) => Show (Quad a) where
  show (Quad a b c d) = show a ++ " " ++ show b ++ "\n" ++ 
                        show c ++ " " ++ show d
instance Functor Quad where 
  fmap f (Quad a b c d) = Quad (f a) (f b) (f c) (f d) 

【问题讨论】:

    标签: haskell type-inference typeclass functor


    【解决方案1】:

    您对Show 的定义要求将show 应用于由Quad 数据构造函数包装的每个值,这会施加约束。如果你有一个像

    这样的微不足道的实例,则不需要它
    instance Show (Quad a) where
        show (Quad a b c d) = "some Quad value"
    

    因为这个定义并不关心 a 等人的类型:

    > show (Quad 1 2 3 4)
    "some Quad value"
    > show (Quad (+1) (+2) (+3) (+4))
    "some Quad value"
    

    另一方面,fmap 具有(a -> b) -> f a -> f b 类型,因为fmap 本身对Quad 使用的类型没有任何限制;任何此类约束都由作为其第一个参数传递给 fmap 的任何函数施加:

    > :t fmap
    fmap :: Functor f => (a -> b) -> f a -> f b
    > :t fmap show
    fmap show :: (Functor f, Show a) => f a -> f String
    

    有时,Functor 的实例需要一个约束。例如,考虑Data.Functor.Compose 中的Compose 类型:

    data Compare f g = Compose { getCompose :: f (g a) }
    

    忽略它的名字,它只需要两个类型为Type -> Type 的类型构造函数。但是,如果您想要 ComposeFunctor 实例,那么这些类型构造函数也必须具有 Functor 实例,因为我们将在内部使用 fmap

    instance (Functor f, Functor g) => Functor (Compose f g) where
        -- x :: f (g a)
        fmap f (Compose x) = Compose (fmap (fmap f) x)
    

    例如,fmap (+1) [1,2,3] == [2,3,4],但fmap (+1) [[1,2,3], [4,5,6]] 不会进行类型检查,因为(+1) 不能将列表作为参数。 Compose 让我们“深入”嵌套仿函数。

    -- Compose [[1,2,3],[4,5,6]] :: Num a => Compose [] [] a
    > fmap (+1) (Compose [[1,2,3], [4,5,6]])
    Compose [[2,3,4],[5,6,7]]
    
    -- Compose [Just 3, Just 4, Nothing] :: Num a => Compose [] Maybe a
    > fmap (+1) (Compose [Just 3, Just 4, Nothing])
    Compose [Just 4,Just 5,Nothing]
    
    -- Compose Nothing :: Compose Maybe g a
    > fmap (+1) (Compose Nothing)
    Nothing
    
    -- Compose (Just [1,2,3]) :: Num a => Compose Maybe [] a
    > fmap (+1) (Compose (Just [1,2,3]))
    Compose (Just [2,3,4])
    

    【讨论】:

    • 非常详细。非常感激。现在就明白了。
    【解决方案2】:

    您在“内部”Quad 类型上调用 show,因此它必须是 Show 的一个实例,但您没有在 fmap 定义中的值“内部”Quad 上调用 fmapQuad 上,所以没有理由要求它是Functor 的一个实例。

    【讨论】:

      猜你喜欢
      • 2016-08-12
      • 2017-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-07
      • 1970-01-01
      相关资源
      最近更新 更多