gpt4 book ai didi

haskell - Haskell 反射中的黑魔法

转载 作者:行者123 更新时间:2023-12-02 01:05:00 24 4
gpt4 key购买 nike

我希望有人能对 Data.Reflection 中的黑魔法有所了解。 。相关片段是:

{-# LANGUAGE CPP #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE KindSignatures #-}

module Data.Reflection
(
Reifies(..)
, reify
) where

import Data.Proxy
import Unsafe.Coerce

class Reifies s a | s -> a where
-- | Recover a value inside a 'reify' context, given a proxy for its
-- reified type.
reflect :: proxy s -> a

newtype Magic a r = Magic (forall (s :: *). Reifies s a => Proxy s -> r)

-- | Reify a value at the type level, to be recovered with 'reflect'.
reify :: forall a r. a -> (forall (s :: *). Reifies s a => Proxy s -> r) -> r
reify a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
  1. 我无法解析 reify 的定义。也许我遗漏了一些关于求值顺序的简单信息,但看起来 unsafeCoerce::a->b 应用于三个参数。
  2. unsafeCoerce 中使用了哪些同构类型?
  3. 函数kreify的定义中实际计算的位置在哪里?
  4. 哪里有 Reifes 的实例?例如,我可以在 GHCi 中运行以下行,仅加载 Data.Reflection 和 Data.Proxy(并设置 -XScopedTypeVariables):。

    reify (3::Int) (\(_::Proxy q) -> print $reflect(Proxy::Proxy q))

  5. 幻影具体化类型在哪里/什么?

  6. newtype Magic 中的“魔法”是什么?

最佳答案

在了解此实现之前,您应该了解 API。最初的想法(反射(reflect)指向类型级别的任意指针)在 this paper 中进行了解释。 ,它在 reflection 的“slow”版本中实现。所以我假设您已经知道它是如何工作的以及如何使用 API。 “fast ”是同一 API 的另一个实现,它使用某种特定于 GHC 的技巧来加快速度。所以:

  1. unsafeCoerce :: a -> b确实应用于三个参数,这意味着 b必须是双参数函数的类型。特别是这个 unsafeCoerce 的类型类似于:Magic a r -> (Proxy s -> a) -> Proxy s -> r .

  2. 呵呵。 “同构”。

    更严肃地说:了解 GHC 类型类的实现非常重要,其中涉及字典传递。当你有类似的事情

    class Num a where
    plus :: a -> a -> a
    negate :: a -> a
    foo :: Num a => a -> a
    foo x = plus x (negate x)

    它被翻译成类似的东西

    data Num a = Num { plus :: a -> a -> a, negate :: a -> a }
    foo :: Num a -> a -> a
    foo dict x = plus dict x (negate dict x)

    当您使用 foo 时,GHC 会根据类型确定要传入的字典。请注意单参数函数如何变成双参数函数。

    所以类型类的实现是传递一个额外的字典参数。但请注意,作为优化,我们可以使用 newtype而不是data当类只有一种方法时。例如

    class Default a where
    def :: a
    doubleDef :: Default a => (a, a)
    doubleDef = (def, def)

    变成了

    newtype Default a = Default { def :: a }
    doubleDef :: Default a -> (a, a)
    doubleDef dict = (def dict, def dict)

    但这生成了def正在运行unsafeCoerce .

  3. Magic k k ,只是类型不同。所以函数unsafeCoerce (Magic k)是函数k ,其类型已修改。都是一样的功能。

  4. 所以让我们考虑一下这个类是如何编译的(我将切换到 Proxy 并用大写 P 来简化事情)。

    class Reifies s a | s -> a where
    reflect :: Proxy s -> a
    foo :: Reifies s a => ...

    变成了

    newtype Reifies s a = Reifies { reflect :: Proxy s -> a }
    foo :: Reifies s a -> ...
    -- which is unsafeCoerce-compatible with
    foo :: (Proxy s -> a) -> ...

    所以,从操作上来说,

    newtype Magic a r = Magic (forall s. Reifies s a => Proxy s -> r)

    unsafeCoerce - 兼容

    newtype Magic a r = Magic (forall s. (Proxy s -> a) -> Proxy s -> r)
  5. 现在我们可以看看它是如何工作的:

    reify获取两个参数,一个值 :: a和一个函数:: forall s. Reifies s a => Proxy s -> r 。由于该函数的形状与 Magic 相同。 ,我们把它变成一个值:: Magic a r 。在操作上,Magic a rforall s. (Proxy s -> a) -> Proxy s -> r 大致相同,这样我们就可以祈祷 unsafeCoerce它。当然,(Proxy s -> a) -> Proxy s -> r同构于 a -> r ,所以我们只需要传入正确的函数( const a )和 Proxy值,我们就完成了。

  6. 神奇之处始终存在于你的函数中。

关于haskell - Haskell 反射中的黑魔法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17793466/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com