簡體   English   中英

如何用“反射”包替換 ImplicitParams?

[英]How to replace ImplicitParams with the 'reflection' package?

我有一個枚舉類型,例如

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約束傳遞的值,例如在應用程序的開頭。

這樣的事情可能嗎? 或者使用reflection庫最接近的近似值是什么?

這回答了實現問題1.使用反射的兩種方法。

使用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仍然生成一個必須“提取”名稱的Proxy

{-# 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"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM