我想定義一個資料型別來編碼具體化的運算式,它也是 Functor 的實體。
在這種情況下,reifiable 可以簡單地意味著運算式可以表示為一個字串,這樣它們以后可以被決議回相同的運算式。在這方面相當于實體化Show。
示例簡化的運算式資料結構:
data Exp x where
ConstInt :: Int -> Exp Int
ConstString :: String -> Exp String
Product :: Exp a -> Exp b -> Exp (a, b)
Apply :: String -> (a -> b) -> Exp a -> Exp b
型別變數對運算式求值時產生的值的型別進行編碼。兩個 Consts 建構式是運算式的葉子。Product 建構式讓我們可以構建更高級別的型別。Apply 建構式用于“提升”常規函式以對運算式進行操作,其中 String 欄位用于標識提升的函式。
提升功能的示例:
swap :: (b, a) -> (a, b)
swap (a, b) = (b, a)
swapExp :: Exp (b, a) -> Exp (a, b)
swapExp = Apply "swap" swap
然后可以構造運算式,例如:
example :: Exp (String, Int)
example = swapExp $ Product (ConstInt 0) (ConstString "string")
為了完整起見,評估者可以采用以下形式:
eval :: Exp x -> x
eval (ConstInt a) = a
eval (ConstString a) = a
eval (Product a b) = (eval a, eval b)
eval (Apply _ f a) = f (eval a)
在這種情況下,實體化 Show 很簡單:
instance Show (Exp x) where
show (ConstInt x) = show x
show (ConstString x) = "\"" show x "\""
show (Product a b) = "(" show a ", " show b ")"
show (Apply name f exp) = name "(" show exp ")"
但是 Functor 無法實作,因為無法命名被提升的函式:
instance Functor Exp where
fmap f exp = Apply "???" f exp
一種可能的解決方案可能是在外部提供從函式(例如交換)到識別符號(例如“交換”)的映射,但我不確定是否/如何完成。
uj5u.com熱心網友回復:
從概念上講,您嘗試做的事情是不可能的。
fmap需要為任何功能、任何功能型別作業。那么如果函式不可具體化會怎樣呢?例如,如果它是由部分應用程式形成的,涉及一個不可具體化的值,比如一個開放的資料庫連接?
你有幾個選擇。
- 您可以放松對an的語意
Exp x將在具體化周期中存活下來的期望。匿名或不可具體化的函式只會被“命名”"<function>",并且會被解封為undefined. 注意:如果你想要一個instance Eq Exp a,你需要確保它符合身份和組合的函子法則。 - 放棄
Functor并定義你自己的expMap。讓它以 anExp (a -> b)作為引數,并為足以啟用所需功能的函式f引入建構式和運算子。Exp - 深入了解 Haskell 中用于嵌入式 DSL 的現代工具。我懷疑點菜資料型別可能會有幫助,但學習如何使用 DTalC 本身就是一個專案。
- 竊取其他需要處理“具體化”功能的人的作業。就在昨天,我不得不弄亂QuickCheck 的功能模塊。這也很難;你的問題是一個老問題,任何解決方案(即使是部分解決方案)都將是“非平凡的”,這意味著需要努力才能理解。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/536681.html
標籤:哈斯克尔
