[英]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
上的操作的方法,保留結構,而不必為每個操作創建特殊情況。
通常,要將功能提升到某種結構中,可以使用Functor
和Applicative
。 但是,執行此操作的直接方法涉及轉換結構並直接應用提升的 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
,就像Applicative
的liftA
一樣。
稍后,我們想通過恢復f
、 x
和y
的值來檢查使用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
實例(取決於“一點額外”是什么,我實際上可能在談論Applicative
或Monad
)。
另一方面,我使用Arrow
實例來談論“少一點的函數”:箭頭讓您可以定義可以以與函數相同的方式組合在一起的事物,但是您可以添加額外的結構或限制以禁止某些構造(例如沒有ArrowChoice
或ArrowLoop
的箭頭)。
您希望完成什么並不完全清楚,但聽起來您實際上是在將數據包裝在AV
類型構造函數中。 在這種情況下,您可能希望使AV
成為Functor
的實例,並為(AV a, AV b) => AV (a, b)
添加Functor
實例,並且類似地為環繞Either
的AV
添加 Functor 實例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.