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

如何用“反射”包替换隐式参数?

  •  0
  • Shersh  · 技术社区  · 5 年前

    我有一个枚举类型,例如。

    data MyType = A | B
    

    我希望能够将这种类型的值隐式地传递给我的函数。我可以用 ImplicitParams GHC扩展如下:

    type HasMyType = (?myType :: MyType)
    
    myFun :: HasMyType => String
    myFun = case ?myType of
        A -> "Foo"
        B -> "Bar"
    

    但我听说过很多次,最好使用Haskell软件包 reflection 完成这项任务。不幸的是 reflection 文档没有解释如何使用库编写类似的代码。要想弄明白这一点并不是那么简单。

    所以,我的问题是,是否有可能使用 反射 库来实现类似的代码并满足以下要求?

    1. 价值观 MyType 应该隐式传递。
    2. 如果 HasMyType 未指定约束,默认值为 MyType 应该采取行动。
    3. 应该可以重写通过 HasMyType 单个位置的约束,例如在应用程序开始时。

    这样的事情可能吗?或者使用 反射 图书馆

    0 回复  |  直到 5 年前
        1
  •  3
  •   Iceland_jack    5 年前

    这回答了两种实现问题的方法 1. 使用 reflection .

    使用 Reifies :

    type HasMyType :: forall k. k -> Constraint
    type HasMyType name = Reifies name MyType
    
    myFun :: HasMyType name => Proxy name -> String
    myFun name = case reflect name of
      A -> "Foo"
      B -> "Bar"
    
    -- reify :: MyType -> (forall name. HasMyType name => Proxy name -> res) -> res
    >> reify A myFun
    "Foo"
    >> reify B myFun
    "Bar"
    >> reify A \name -> myFun name
    "Foo"
    >> reify B \name -> myFun name
    "Bar"
    

    Haskell还不能抽象类型变量 \@name -> .. 所以它使用 \(Proxy :: Proxy name) -> .. .

    这个 Proxy 可以从 myFun 哪里 name 提供了可见类型的应用程序,但 reify 仍然会产生 代理 谁的名字必须是“提取的”

    {-# Language ScopedTypeVariables #-}
    {-# Language TypeApplications #-} ..
    
    myFun :: forall name. HasMyType name => String
    myFun = case reflect @name Proxy of
      A -> "Foo"
      B -> "Bar"
    
    >> reify A \(_ :: _ name) -> myFun @name
    "Foo"
    >> reify B \(_ :: _ name) -> myFun @name
    "Bar"
    

    更简单的选择( Given )不依赖类型级别的“名称”来区分不同的字典,因此使用以下警告更危险:

    对于每种类型,您应该只给出一个值。如果范围内有多个实例,则行为由实现定义。

    type HasMyType :: Constraint
    type HasMyType = Given MyType
    
    myFun :: HasMyType => String
    myFun = case given of
      A -> "Foo"
      B -> "Bar"
    
    -- give :: MyType -> (HasMyType => res) -> res
    >> give A myFun
    "Foo"
    >> give B myFun
    "Bar"
    
    推荐文章