You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中Constant类型的两个Functor实例为何类型检查结果不同?

Why do these two Functor instances for Constant have different type-checking results?

Let's break down exactly why one instance works and the other throws a type error, starting with core Haskell type system constraints.

First, let's recap the definitions and signatures we're working with:

  • The newtype: newtype Constant a b = Constant { getConstant :: a } deriving (Eq, Show)
  • The Functor type class requires fmap :: (b -> c) -> f b -> f c. For Functor (Constant a), this specializes to:
    fmap :: (b -> c) -> Constant a b -> Constant a c
    

Why the first instance works

The first implementation uses pattern matching to deconstruct and reconstruct the Constant value:

instance Functor (Constant a) where
  fmap _ (Constant x) = Constant x

Here's what happens during type checking:

  1. We pattern match on Constant x, where x has type a (since getConstant returns a).
  2. When we reconstruct Constant x, the constructor Constant has the polymorphic type a -> Constant a c—it can produce a Constant value for any type c (the second type parameter of the newtype).
  3. The type system infers that the returned Constant x should have type Constant a c (matching the fmap signature's return type), which is perfectly valid because the constructor lets us pick any c we need. We're not reusing the input value directly—we're building a logically identical value with the correct type parameter, so the input Constant a b and output Constant a c play nicely together.

Why the second instance fails

The second implementation tries to return the input value directly:

instance Functor (Constant a) where
  fmap _ x = x

This runs into a type mismatch because:

  1. The input x has type Constant a b (from the fmap signature's second parameter).
  2. The fmap signature requires returning a value of type Constant a c.
  3. For x to be valid as the return value, the type system would need Constant a b to equal Constant a c—meaning b ~ c (b must be the same type as c). But this violates fmap's polymorphic contract: fmap is supposed to work for any types b and c, not just when they're identical.

GHC can't reconcile this unspoken constraint, so it throws an error saying it expected Constant a b but got Constant a a1 (or similar)—because it can't unify the two distinct type variables for the newtype's phantom second parameter.

Key takeaway

Even though Constant a b and Constant a c share the same runtime representation (since the second type parameter is phantom), Haskell's type system treats them as distinct types. Pattern matching and reconstructing lets you leverage the constructor's polymorphism to produce a value with the correct type parameter. Returning the input directly traps you with the original type parameter, which doesn't match what fmap promises to return.

内容的提问来源于stack exchange,提问作者Timo Denk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:27:18