給定具有固定點的任意數據結構,我們可以構造一個monoidal代數而無需手動指定所有情況嗎?固定點上的Monoidal褶皺
假設我們得到如下的數據類型Expr
。使用庫,我們可以派生出一個基函數ExprF
,它自動也有Functor
,Foldable
和Traversable
實例。
{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TemplateHaskell #-}
import Data.Semigroup (Sum(..))
import Data.Functor.Foldable
import Data.Functor.Foldable.TH
import Prelude hiding (fail)
data Expr = Var String
| Const Int
| Add [Expr]
| Mult [Expr]
deriving Show
$(makeBaseFunctor ''Expr)
expr :: Fix ExprF
expr = ana project $ Add [Const 1, Const 2, Mult [Const 3, Const 4], Var "hello"]
現在,讓我們說,我們希望計算expr
葉片數。我們可以很容易地編寫一個代數這樣一個小數據結構:現在
alg (ConstF _) = 1
alg (VarF _) = 1
alg (AddF xs) = sum xs
alg (MulF xs) = sum xs
,我們可以稱之爲cata alg expr
,它返回5
,正確的結果。
讓我們假設Expr
增長真的很大,也很複雜,我們不想爲所有數據構造函數手動編寫案例。 cata
如何知道如何結合所有案例的結果?我懷疑這是可能的,使用Monoid
s,可能與Const
仿函數(雖然不完全確定最後一部分)。
fail = getSum $ foldMap (const (Sum 1) . unfix) $ unfix expr
fail
回報4
,而我們實際上有5
葉子。我認爲問題在於固定點,因爲我們只能剝離一層Fix
ing,因此Mult [..]
只計爲一片葉子。
是否有可能以某種方式摺疊一般在整個固定點和不手動指定所有實例Monoid
樣結構收集結果嗎?我想要的是一種foldMap
,但採用更通用的方式。
我有一種感覺,我失去了一些真正明顯的東西。
'fail'計算'expr'頂部節點的子節點。一般來說,它離樹葉不遠。這不是合適的'cata'的'alg'。 – pigworker
@pigworker我有同樣的懷疑。現在我所尋找的是一個積累的變形,我不必爲60個案例(每個構造函數一個)編寫,而是在遞歸案例中使用monoid屬性。我覺得這應該是可能的,但我不知道如何去解決這個問題。 – ThreeFx
葉的特徵是其子女的葉計數總和爲零,因爲沒有孩子。現在,考慮到孩子的葉子數(總和),你能計算父親的葉子數嗎? – pigworker