代码之家  ›  专栏  ›  技术社区  ›  Zazaeil

`(a->b)->(c->d)`在哈斯克尔?

  •  4
  • Zazaeil  · 技术社区  · 7 年前

    让我们举一个简单而著名的例子。 fmap ? 所以 fmap :: (a -> b) -> f a -> f b ,忽略了以下事实: f 实际上是一个 Functor . 据我了解,, (a -> b) -> f a -> f b 只不过是一个 语法糖 对于 (a -> b) -> (f a -> f b) ; 因此得出结论:

    (1) fmap 是一个产生函数的函数。

    现在 哈斯克 也包含函数,因此 (a -> b) 特别是,, (f a -> f b) 是 物件 Hask(因为Hask的对象是定义良好的Haskell类型-a-ka数学集-并且确实存在类型集) 每种可能 a 对吧?。因此,再一次:

    (2) (a->b)

    现在奇怪的事情发生了: fmap 态射 它是一个函数,它接受另一个函数并将其转换为另一个函数; 最终功能尚未应用 .

    因此,还需要一个Hask态射才能从 (f a->f b) 到 f b . 每一项 i A. 存在一个态射 apply_i :: (f a -> f b) -> f b 定义为 \f -> f (lift i) 哪里 lift i 是建立一个 f a 特别 我

    另一种看法是 GHC -风格: (a->b)>f a->f-b . 与我上面写的相比, (a -> b) -> f a 映射到Hask的常规对象。但这种观点与哈斯克尔的基本公理相矛盾——没有多元函数,而是应用(curried)的替代方案。


    在这一点上我想问:是吗 (a->b)>f a->f-b 假设是一个 (a -> b) -> (f a -> f b) -> f b 或者我错过了一些非常非常重要的东西?

    4 回复  |  直到 7 年前
        1
  •  6
  •   leftaroundabout    7 年前

    是 (a -> b) -> f a -> f b (a -> b) -> (f a -> f b) -> f b ,加糖是为了简单

    (a -> b) -> (f a -> f b) 态射 以与外部相同的方式 (a -> b) -> (f a -> f b) 可以函子类的一般情况是(伪语法)

    class (Category (──>), Category (~>)) => Functor f (──>) (~>) where
      fmap :: (a ──> b) -> f a ~> f b
    

    因此,它映射类别中的态射,其箭头被表示 ──> 范畴中的态射 ~> ,但这个态射映射本身只是一个简单的例子 作用 哈斯克 具体来说,函数箭头与态射箭头是同一种箭头,但从数学上讲,这是一种相当退化的情况。

        2
  •  5
  •   chepner    7 年前

    fmap 实际上是一个整体 家庭 关于态射。中的态射 哈斯克 始终从一个混凝土类型转换为另一个混凝土类型。如果函数具有具体的参数类型和具体的返回类型,则可以将函数视为态射。类型函数 Int -> Int 表示来自的态射(实际上是自同态) Int 到 Int 在里面 哈斯克 . fmap ,但有类型 Functor f => (a -> b) -> f a -> f b . 看不到一个具体的类型!我们只有类型变量和一个拟算子 => 处理。

    考虑下面的一组具体的函数类型。

    Int -> Int
    Char -> Int
    Int -> Char
    Char -> Char
    

    进一步,考虑以下类型的构造函数

    []
    Maybe
    

    [] 适用于 Int 返回我们可以调用的类型 List-of-Ints ,但我们通常只是打电话 [Int] Maybe Int 返回我们刚才调用的类型, .

    现在,我们可以定义一组函数,如下所示

    fmap_int_int_list :: (Int -> Int) -> [Int] -> [Int]
    fmap_int_char_list :: (Int -> Char) -> [Int] -> [Char]
    fmap_char_int_list :: (Char -> Int) -> [Char] -> [Int]
    fmap_char_char_list :: (Char -> Char) -> [Char] -> [Char]
    fmap_int_int_maybe :: (Int -> Int) -> Maybe Int -> Maybe Int
    fmap_int_char_maybe :: (Int -> Char) -> Maybe Int -> Maybe Char
    fmap_char_int_maybe:: (Char -> Int) -> Maybe Char -> Maybe Int
    fmap_char_char_maybe :: (Char -> Char) -> Maybe Char -> Maybe Char
    

    每一个都是一个不同的态射 但是当我们在Haskell中定义它们时,会有很多重复。

    fmap_int_int_list f xs = map f xs
    fmap_int_char_list f xs = map f xs
    fmap_char_int_list f xs = map f xs
    fmap_char_char_list f xs = map f xs
    fmap_int_int_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
    fmap_int_char_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
    fmap_char_int_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
    fmap_char_char_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
    

    当类型为 f 仅当 x / xs 不同。这意味着我们可以定义以下内容 功能

    fmap_a_b_list f xs = map f xs
    fmap_a_b_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
    

    其中的每一个表示一组 哈斯克 .

    fmap 它本身是一个总括术语,我们用来指代所有多态函数所指的特定于构造函数的态射。

    有了这些,我们就能更好地理解 fmap :: Functor f => (a -> b) -> f a -> f b .

    鉴于 fmap f ,我们首先看看 F . 例如,我们可能会发现 f :: Int -> Int ,这意味着 fmap f fmap_int_int_list fmap_int_int_maybe ,但我们还不确定是哪个。因此,它返回一个 受限 类型函数 Functor f => (Int -> Int) -> f Int -> f Int [内部] 或 也许是Int ,我们最终会有足够的信息来知道哪个态射是真正的意思。

        3
  •  3
  •   Community Mohan Dere    6 年前

    现在奇怪的事情发生了:显然,fmap是Hask的一个态射,所以它是一个函数,它接受另一个函数并将它转换成另一个函数;最终功能尚未应用。

    因此,我们还需要一个Hask的态射才能从(fa->fb)到fb。对于类型a的每个项目i,都存在一个态射apply_i:(f a->f b)>定义为\f->f(lift i),其中lift i是一种构建内部具有特定i的fa的方法。

    范畴理论中的应用概念是以 CCC's - Cartesian Closed Categories . 如果你有一个自然双射(XY,Z)(X,YZ),类别就是CCC。

    因此,我们还需要一个Hask的态射才能从(fa->fb)到fb。

    你从何而来 (f a -> f b) f b ,或使用上述符号,从 (f a ⇒ f b) 是通过 𝜺[f a,f b]:(f a ⇒ f b) × f a → f b .

    另一个需要记住的要点是,在范畴理论中,“元素”不是原始概念。相反,元素是形式为ðŸŸа–†аX的箭头,其中ðŸа是终端对象。如果你用X=Y,你就得到了(Y,Z)–Y,Z)。也就是说,态射g:Y††Z是对元素的双射。

    在Haskell中,这意味着函数正是箭头类型的“元素”。所以在Haskell中有一个应用程序 h y 将通过在y:y上对h:(YZ)的求值来建模。也就是说,对(h)y:(YZ)y的求值,由组成(h)y给出;[Y,Z]:Z。

        4
  •  2
  •   duplode    7 年前

    为了完整起见,本答案侧重于各种评论中提到的一点,而不是其他答案。

    另一种方式是GHC风格: (a -> b) -> f a -> f b . 与我上面写的相比, (a -> b) -> f a 映射到Hask的常规对象。

    -> (a->b)>f a->f-b 真的和 (a -> b) -> (f a -> f b) (a->b)>f a

    (++) :: [a] -> [a] -> [a]
    

    ... 这并不意味着部分应用 (++) 会给我们一个 [a] list(相反,它为我们提供了一个函数,该函数在一些list之前加上前缀)。

    从这个角度来看,你提出的范畴理论问题(例如,关于“需要更多哈斯克的态射才能从 (f a -> f b) 到 f b )是一个单独的问题,由 Jorge Adriano's answer

    推荐文章