簡體   English   中英

Haskell 中的泛型類型轉換

[英]Generic type transformations in Haskell

我正在嘗試編寫一個帶有常規函數的箭頭轉換器,並將它們轉換為抽象值的計算。 如果我們有一個“源”箭頭,

f :: Int -> Int
f x = x + 1

那么目標是讓f處理提升的 [原文如此?] 抽象值類型,在這個例子中

f' :: AV Int -> AV Int
f' (Const x) = Const (f x)
-- pass along errors, since AV computation isn't always defined
-- or computable in the case of errors
f' (Error s) = Error s
-- avRep = "abstract representation". Think of symbolic math manipulation or ASTs.
f' (Abstract avRep) = AVRepPlus avRep (AVRepConst 1)

然而,為了成功地實現這個箭頭,需要提升一些類型,以便在任意深度擁有具有一些具體值和一些抽象值的異構數據結構 我最終做的是為常規 haskell 構造函數添加特殊類型,例如,如果

g = uncurry (+) -- i.e. g (x, y) = x + y

然后我為元組構造函數 (,) 添加一個抽象表示,

AVTuple :: AV a -> AV b -> AV (a, b)

並且g的代碼被提升到 [展開一點],

g' (AVTuple (AVConst a) (AVConst b)) = (AVConst (g (a, b)))
g' (AVTuple (AVError e) _) = (AVError e)
-- symmetric case here, i.e. AVTuple _ (AVError e)
g' (AVTuple a@(AVTuple _ _) b) = -- recursive code here

AVEither 也需要這樣做。 這最終會成為很多案例。 有沒有一個很好的方法來解決這個問題?

我是 Haskell 新手,所以請發給我參考資料或半詳細說明; 可能我讀過的最接近的東西是 SYBR 論文(廢棄你的樣板革命)第 1-3 節。

非常非常感謝你!

讓我看看我是否明白你在這里的目的。 你有一個類型AV a ,它描述了一個產生類型a的計算,其中該計算的結構可以以允許檢查的方式保留。 您想要一種將任意函數提升到AV上的操作的方法,保留結構,而不必為每個操作創建特殊情況。

通常,要將功能提升到某種結構中,可以使用FunctorApplicative 但是,執行此操作的直接方法涉及轉換結構並直接應用提升的 function,而不是將 function 應用程序保留為結構的一部分。

你想要的更尷尬,原因如下:

假設我們有一些我們想要提升的 function 和兩個適當類型的抽象值來應用它:

x :: AV A
x = ...

y :: AV B
y = ...

f :: A -> B -> C
f = ...

假設存在一個 function liftAV2您的需求。 我們希望lift2 f的類型是AV A -> AV B -> AV C ,就像ApplicativeliftA一樣。

稍后,我們想通過恢復fxy的值來檢查使用lift2 f產生的計算。 假設現在我們只想提取第一個參數。 假設存在執行此操作的 function extractArg1 ,這樣extractArg1 (liftAV2 fxy) = x extractArg1的類型是什么? 在這里,在context 中,我們知道它的類型應該是AV C -> AV A 但它一般有什么類型? AV c -> AV a類的東西? 這是錯誤的,因為結果不僅僅是任何類型a ,它是用於構造AV c值的任何類型。 假設我們正在操作的值是使用liftAV2 f的結果構造的,我們知道存在問題的類型,但我們一般無法找到它。

這就是我們進入存在主義類型領域的地方。 誠實地使用它們,而不是像通常那樣將它們與類型類一起濫用。

你也許可以通過一些努力來完成你所追求的,但這已經進入了相當先進的領域。 您將希望使用GADT作為初學者,盡管我認為您可能已經在這樣做了。 使用存在類型也往往非常笨拙,因為您只能在有限的上下文中知道它們是什么。

在您的特定情況下,為AV提供兩個類型參數可能更容易:一個代表計算的最終類型,一個代表計算的結構,例如:

data f :$ x = ...

data AV structure result where
    ...
    AVApply :: AV f (a -> b) -> AV x a -> AV (f :$ x) b

然后,為了檢查計算,您可以查看第一種類型以了解您擁有什么; 為了構建計算,您可以查看第二個以確保類型匹配。 評估 function 將具有類似AV ta -> a的類型,丟棄結構。 你也可以使用結構類型“解包”計算,丟棄結果類型,如果你需要拆開結構以便漂亮地打印它。

我喜歡思考它的方式,當我想談論一些“帶有一點額外的數據”時,我會使用Functor實例(取決於“一點額外”是什么,我實際上可能在談論ApplicativeMonad )。

另一方面,我使用Arrow實例來談論“少一點的函數”:箭頭讓您可以定義可以以與函數相同的方式組合在一起的事物,但是您可以添加額外的結構或限制以禁止某些構造(例如沒有ArrowChoiceArrowLoop的箭頭)。

您希望完成什么並不完全清楚,但聽起來您實際上是在將數據包裝在AV類型構造函數中。 在這種情況下,您可能希望使AV成為Functor的實例,並為(AV a, AV b) => AV (a, b)添加Functor實例,並且類似地為環繞EitherAV添加 Functor 實例。

暫無
暫無

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

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