【问题标题】:Why is (a, a) not a functor? [duplicate]为什么 (a, a) 不是函子? [复制]
【发布时间】:2012-10-06 11:45:40
【问题描述】:

可能重复:
Making (a, a) a Functor

我写了下面的快速排序实现:

import Data.List (partition)

quicksort [] = []

quicksort (x:xs) =
    let (smaller, notSmaller) = partition (< x) xs
    in  quicksort smaller ++ x : quicksort notSmaller

然后我想通过将fmap 应用于列表对来缩短对quicksort 的两个递归调用:

quicksort (x:xs) =
    let (smaller, notSmaller) = fmap quicksort $ partition (< x) xs
    in  smaller ++ x : notSmaller

但显然,(a, a) 不是函子。这是为什么?我试着提供一个:

instance Functor (a, a) where
    fmap f (x, y) = (f x, f y)

但是 ghci 不喜欢我的尝试:

Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `(a, a)' has kind `*'
In the instance declaration for `Functor (a, a)'

谁能向我解释这个错误?我尝试了各种“修复”,但都没有奏效。

是否可以使(a, a) 成为Functor 的实例?还是类型系统不够表达?

【问题讨论】:

    标签: haskell typeclass functor type-systems


    【解决方案1】:

    重要的是要意识到不是(a,a) 是函子,就像Maybe a[a] 不是函子一样。相反,函子是Maybe[]

    完整的解释需要引入种类的概念,类似于“类型的类型”。任何具体类型都有*。像Maybe[] 这样的类型构造函数 接受一个类型并返回另一个类型,所以它有一种* -&gt; *

    (,)(pair 的构造函数)是什么类型的?它需要两种类型,一种用于第一个插槽,一种用于第二个插槽,所以它有 kind * -&gt; * -&gt; *

    你只能用类似* -&gt; * 的东西来制作函子,所以对你的问题的简短回答是,你不能将(,) 变成函子。

    但是,您可以通过包装类型来绕过限制。例如

    newtype Pair a = P (a,a)
    
    instance Functor Pair where
        fmap f (P (x,y)) = P (f x, f y)
    

    newtype 包装器将被编译器优化掉,因此这并不比您最初尝试做的更昂贵 - 只是更冗长一些。

    【讨论】:

    • 啊哈,我试过type Pair a = (a, a),但没用。
    • @FredOverflow type 与 C++ 中的 typedef 类似;它不会创建一个新类型,只是一个别名(所以它不会有任何区别)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多