25 F-Algebras (Sketch)
เราได้เห็นการกำหนดรูปสูตรหลายแบบของmonoid ในฐานะset ในฐานะcategoryที่มีวัตถุเดี่ยว ในฐานะวัตถุในcategoryแบบmonoidal เราสามารถจะดึงสิ่งที่น่าสนใจออกมาได้เท่าไหร่จากแนวคิดที่เรียบง่ายนี้
เรามาลองดู นำนิยามนี้ของmonoidในฐานะset
ในที่นี้
productแบบCartesianของสองชุดเหล่านี้คือ
ในการใช้พีชคณิตในระดับมัธยม(ที่ใช้งานได้ใรทุกๆcategoryแบบclosedและCartesian) เราสามารถเขียนใหม่ได้ว่า
ในเครื่องหมาย
สมาชิกใดๆก็ตามของsetเหล่านี้ของfunctionsนั้นเป็นสิ่งที่เป็นไปได้ที่จะเป็นmonoid
ความสวยงามของการแปลงแบบนี้คือการที่ว่ามันนำไปสู่การgeneralizeที่น่าสนใจ ตัวอย่างเช่น อะไรคือวิธีการที่เราจะอธิบายgroupโดนการใช้ภาษานี้? groupคือmonoidที่มีหนึ่งfunctionมากขึ้นที่กำหนดinverseไปกับทุกสมาชิก ส่วนหลังคือfunctionของtype
เหมือนก่อนหน้านี้ เราสามารถรวมสามตัวเหล่านี้ไปยังชุดของfunctions
เราเริ่มมากับoperatorแบบbinaryตัวหนึ่ง(การบวก) operatorแบบunary(negation)และoperatorแบบnullaryตัวหนึ่ง(identityที่ในที่นี้คือศูนย์) เราได้รวมมันไปยังfunctionหหนึ่ง ในทุกๆfunctionsกับsignatureนี้นิยามgroupsที่เป็นไปได้
เราสามารถไปยังแบบนี้ ตัวอย่างเช่นในการนิยามring เราอาจจะเพิ่มoperatorแบบbinaryหนึ่งและoperatorแบบnullaryหนึ่งและอื่นๆ ในแต่ละครั้งเราจบลงที่typeของfunctionที่ทางด้านช้ายคือการบวกของสิ่งที่ยกกำลัง(ก็อาจจะรวมไปถึงยกกำลัง)และในทางด้านขวาเป็นsetตัวมันเอง
ในตอนนี้เราสามารถไปอย่างสุดเหวี่ยงกับการgeneralize ตัวอย่างเช่น เราสามารถแทนที่setsกับวัตถุและfunctionsกับmorphisms เราสามารถนิยามoperatorsแบบn-aryในฐานะmorphismsจากproductsแบบn-ary มันหมายความว่าเราต้องการcategoryที่สามารถรับรองproductsที่มีที่สิ้นสุด สำหรับoperatorsแบบnullaryเราต้องการการมีอยู่ของวัตถุสุดท้าย ดังนั้นเราต้องการcategoryแบบCartesian ในการที่ได้จะรวมoperatorsเหล่านี้ เราต้องการexponentials ดังนั้นคือcategoryแบบCartesian closed สุดท้ายแล้ว เราต้องการcoproductsในการทำให้การเล่นกับพีชคณิตนั้นจบชักที่
ในทางกลับกัน เราสามารถแค่ลืมเกี่ยวกับวิธีการที่เราหาสูตรของเราและเพ่งเล็งไปยังproductสุดท้าย ผลบวกของproductsในด้านช้ายของmorphismของเราได้นิยามendofunctor ถ้าเราเลือกendofunctor
F-algebraคือtripleที่ประกอบด้วยendofunctor
วัตถุนั้นมันจะถูกเรียกว่าcarrier วัตถุข้างใต้หรือในบริบทของการเขียนโปรแกรมคือtypeของcarrier morphismนั้นมักจะถูกเรียกว่าfunctionการประเมินหรือmapโครงสร้าง คิดถึงfunctor
ในที่นี้นิยามของHaskellของF-algebra
type Algebra f a = f a -> a
มันตรงกับalgebraกับfunctionการประเมิน
ในตัวอย่างของmonoid functorที่เราสนใจคือ
data MonF a = MEmpty | MAppend a a
นี้คือHaskellสำหรับ
ringอาจจะถูกนิยามโดยการใช้functorเหล่านี้
data RingF a = RZero
| ROne
| RAdd a a
| RMul a a
| RNeg a
ที่ในHaskell
มันคือตัวอย่างสำหรับringคือsetของintegers เราสามารถเลือกInteger
ในฐานะtypeแบบcarrierและนิยามfunctionว่า
evalZ :: Algebra RingF Integer
RZero = 0
evalZ ROne = 1
evalZ RAdd m n) = m + n
evalZ (RMul m n) = m * n
evalZ (RNeg n) = -n evalZ (
ได้มีF-algebrasมากขึ้นที่มาจากfunctorเดียวกันRingF
ตัวอย่างเช่นpolynomialsก่อให้เกิดringและรวมไปถึงmatricesกำลังสอง
ในที่คุณได้เห็น บทบาทของfunctorนั้นในการสร้างexpressionsที่สามารถถูกประเมินของalgebra ถึงในตอนนี้แล้ว เราได้แต่เห็นexpressionsที่เรียบง่าย เรานั้นมักจะสนใจในexpressionsที่ซับซ้อนมากขึ้นที่สามารถถูกนิยามโดยการใช้recursion
25.1 Recursion
วิธีหนึ่งในการสร้างtrees expressionทั่วๆไปคือการแทนที่ตัวแปลa
ภายในนิยามของfunctorกับrecursion ตัวอย่างเช่นexpressionทั่วๆไปในringนั้นสร้างโดยdata structureแบบtreeอย่าง
data Expr = RZero
| ROne
| RAdd Expr Expr
| RMul Expr Expr
| RNeg Expr
เราสามารถแทนที่ตัวประเมินringเริ่มต้นกับรูปแบบrecursive
evalZ :: Expr -> Integer
RZero = 0
evalZ ROne = 1
evalZ RAdd e1 e2) = evalZ e1 + evalZ e2
evalZ (RMul e1 e2) = evalZ e1 * evalZ e2
evalZ (RNeg e) = -(evalZ e) evalZ (
สิ่งนี้นั้นไม่มีผลในมาปฏิบัติเพราะว่าเรานั้นถูกบังคับในการแสดงแทนทุกๆจำนวนเต็มในฐานะการบวกกันของเลขหนึ่งแต่มันจะเป็นสิ่งที่จำเป็น
แต่อะไรคือวิธีการที่เราจะอธิบายexpression treesโดยการใช้ภาษาของF-algebras? เราต้องการในแบบไดก็ตามที่ทำให้เป็นสูตรของขบวนการของการแทนที่ตัวแปลtypeอิสระในนิยามของคำนิยามของfunctorของเราในแบบrecursively คู่กับผลของการแทนที่ ลองจินตนาการการทำนี้ให้เป็นขั้น เริ่มแรกนิยามtreeที่มีความลึกเท่ากับหนึ่งว่า
type RingF1 a = RingF (RingF a)
เรากำลังเติมเต็มหลุมในนิยามของRingF
กับtreeที่ไม่มีความลึกที่สร้ามมาโดยRingF a
treeที่มีความลึกเท่ากับสองสามารถได้มาอย่างเดี่ยวกัน
type RingF2 a = RingF (RingF (RingF a))
ที่เราก็สามารถถูกเขียนว่า
type RingF2 a = RingF (RingF1 a)
ทำตามขบวนนี้เราสามารถเขียนในสมการทางสัญลักษณ์ว่า
type RingF_{n+1} a = RingF (RingF_{n} a)
ในแนวคิด หลังจากการทำขบวนการนี้ช้ำหลายๆครั้งเราจะจบที่Expr
ของเรา สังเกตว่าExpr
ไม่ได้ขึ้นกับa
จุดเริ่มแรกของการเดินทางของเราไม่สำคัญ เราก็จะกลับมาที่เดิมเสมอ นี้นั้นไม่ถูกต้องเสมอไปสำหรับendofunctorทั่วๆไปในcategoryทั่วๆไปแต่สิ่งต่างๆในcategory
แน่นอนว่านี้คือข้อโต้เถียงที่ไม่เข้มงวดและผมจะทำให้มันนั้นเข้มงวดมากขึ้นหลังจากนี้
การใช้endofunctorหลายๆครั้งไม่มีที่สิ้นสุดได้สร้างจุดคงที่(fixed point)และวัตถุนั้นถูกนิยามโดย
แนวคิดข้างหลังนิยามนี้คือว่า เนิื่องว่าเราได้ทำการใช้งาน
newtype Fix f = Fix (f (Fix f))
กล่าวได้ว่า นี้อาจจะอ่านได้ง่ายกว่าถ้าชื่อของconstructorนั้นแตกต่างจากชื่อของtypeที่ถูกนิยามในว่า
newtype Fix f = In (f (Fix f))
แต่เราจะคงอยู่กับสัญลักษณ์ที่ได้รับการยอมรับ การสร้างFix
(หรือIn
ถ้าคุณชอบมากกว่า)สมารถถูกมองในฐานะfunction
Fix :: f (Fix f) -> Fix f
นั้นก็คือfunctionที่ปลอกชั้นๆหนึ่งของการใช้งานของfunctor
unFix :: Fix f -> f (Fix f)
Fix x) = x unFix (
สองfunctionนั้นคือinverseซึ่งกันและกันห เราจะใช้functionsเหล่านี้ภายหลัง
25.2 CategoryของF-Algebra
นี้คือเคล็ดลับที่เก่าที่สุดในหนังสือเล่มนี้คือไม่ว่าคุณจะคิดได้ว่าเกี่ยวกับวิธีการการสร้างวัตถุใหม่ ต้องดูที่ว่าพวกมันก่อให้เกิดcategoryหรือเปล่า ไม่แปลกใจที่algebraข้างบนendofunctor
ในการที่ทำให้ภาพรวมสมบูรณ์ เราต้องการที่จะนิยามmorphismsในcategoryของF-Algebra morphismต้องโยงalgebra
แล้สเราก็ตามมันไปกับ
มันง่ายมากที่จะทำให้เรามั่นใจว่านี้คือcategoryแน่นอน(คำใบ้: morphisms identityจาก
วัตถุเริ่มต้นในcategoryของF-algebras ถ้ามันมีอยู่จะถูกเรียกว่าalgebraเริ่มต้น(initial algebra) เรามาเรียกcarrierของalgebraเริ่มต้น
ในตอนนี้เรามาสร้างalgebraที่carrierคือ
เพราะว่า
แต่เราก็ต้องมีdiagramที่commutingอย่างง่ายๆ(เส้นทางทั้งสองต้องเหมือนกัน)คือ
ที่สามารถถูกตีความในฐานะการแสดงว่า
ในทางกลับกันdiagramนี้อาจจะถูกตีความในฐานะการแสดงว่า
แต่นั้นคือแค่การพูดว่า
กลับมาในHaskellที่เราสามารถมองFix f
Fix
และinverseของมันในฐานะunFix
isomorphismในtheoremของLambekบอกเราว่า ในการที่ได้มายังalgebraเริ่มต้น เรานำfunctorFix f
เราก็เห็นว่าทำไมจุดคงที่ไม่ได้ขึ้นอยู่กับ
25.3 จำนวนธรรมชาติ
จำนวนธรรมชาติก็สามารถถูกนิยามในฐานะF-algebra จุดเริ่มต้นคือคู่ของmorphisms
ส่วนแรกทำการเลือกเลขศูนย์และส่วนที่สองโยงทุกๆเลขไปยังสิ่งที่ตามมาของพวมมัน เหมือนก่อนหน้านี้ เราสามารถรวมสองตัวไปยังหนึ่งตัว
ในด้านช้ายนิยามfunctorที่ในHaskellสามารถถูกเขียนในแบบนี้
data NatF a = ZeroF | SuccF a
จุดคงที่ของfunctorนี้(algebraเริ่มต้นที่มันสร้าง)สามารถถูกเขียนในHaskellว่า
data Nat = Zero | Succ Nat
จำนวนธรรมชาตินั้นคือเลขศูนย์หรือเป็นสิ่งต่อเนื่องของอีกจำนวนหนึ่ง สิ่งนี้รู้จักในฐานะตัวอย่างของจำนวนธรรมชาติแบบPeano
25.4 Catamorphisms
เรามาเขียนใหม่เงื่อนไขเริ่มต้นโดยการใช้การเขียนแบบHaskell เราเรียกalgebraเริ่มต้นFix f
ตัวประเมินค่าคือconstructorFix
ได้มีmorphismที่เป็นเอกลักษณ์m
จากalgebraเริ่มต้นไปยังalgebraอื่นๆที่อยู่ในfunctorเดี่ยวกัน เรามาเลือกalgebraที่carrierของมันคือa
และตัวประเมินค่าคือalg
อนึ่งสังเกตสิ่งที่m
เป็นคือตัวประเมินค่าของจุดคงที่คือตัวประเมินค่าสำหรับ expression treeแบบrecursiveทั้งหมด เรามาหาวิธีการทั่วๆไปในการเขียนมัน
theoremของLambekบอกเราว่าconstructorFix
นั้นคือisomorphism เราเรียกinverseของมันว่าunFix
ดังนั้นเราสามารถกลับลูกศศรหนึ่งของdiagramนี้เพื่อได้สิ่งนี้มา
เรามาเขียนเงื่อนไขของการcommutationสำหรับdiagramนี้
= alg . fmap m . unFix m
เราสามารถตีความสมการนี้ในฐานะนิยามแบบrecursiveของm
การrecursionนั้นถูกทำให้หยุดลงสำหรับtreeที่จำกัดใดๆก็ตามที่ถูกสร้างโดยการใช้functorf
เราสามารถมองเห็นว่าโดนการที่เราสังเกตว่าFix m
ทำงานภายใต้ชั้นด้านบนจองfunctorf
ในอีกความหมายหนึ่ง มันทำงานได้บนchildrenของtreeดั้งเดิม childrenต่างๆกันนั้นจะมีขนากน้อยกว่าหนึ่งชั้นเมื่อเทียบกับtreeดั้งเดิมโดนตลอด
ในที่นี้สิ่งที่เกิดขึ้นในตอนที่เราทำการใช้m
ไปยังtreeที่ถูกสร้างโดยการใช้Fix f
การกระทำของunFix
ที่เลาะออกของconstructor การเปิดเผยชั้นข้างบนของtree เราก็ต้องก็ทำการใช้m
ไปยังทุกchildrenของnodeด้านบน สิ่งนี้สร้างผลลัพธ์ของtypea
ในที่สุดแล้ว เราจะรวมผลลัพธ์เหล่านี้โดยการทำการใช้ตัวประเมินที่ไม่recursivealg
จุดที่สำคัญคือว่าตัวประเมินalg
ของเรานั้นเป็นfunctionง่ายๆที่ไม่recursive
เนื่องด้วยที่เราสามารถทำได้สำหรับalgebraalg
มันสมเหตุสมในการนิยามfunctionแบบ higher orderที่นำalgebraในฐานะparameterและให้functionกับเรา เราเรียกว่าm
functionแบบ higher orderนั้นถูกเรียกว่าcatamorphism
cata :: Functor f => (f a -> a) -> Fix f -> a
= alg . fmap (cata alg) . unFix cata alg
เรามาเห็นตัวอย่างที่ว่า นำfunctorที่นิยามจำนวนธรรมชาติ
data NatF a = ZeroF | SuccF a
เรามาเลือก(Int, Int)
ในฐานะtypeแบบcarrierและนิยามalgebraของเราว่า
fib :: NatF (Int, Int) -> (Int, Int)
ZeroF = (1, 1)
fib SuccF (m, n)) = (n, m + n) fib (
เราสามารถทำให้เชื่อมั่นว่าcatamorphismสำหรับalgebraนี้catafib
ถูกคำนวณตัวเลขFibonacci
โดนทั่วไป algebraสำหรับNatF
นิยามความสัมพันธ์แบบrecurrenceคือ ค่าของสมาชิกในตอนนี้ในรูปแบบของสมาชิกก่อหน้านี้ catamorphismก็ทำการประเมินมาขิกตัวที่nแบบต่อเนื่องแบบนั้น
25.5 Folds
listของe
นั้นคือalgebraเริ่มต้นสำหรับfunctorแบบนี้
data ListF e a = NilF | ConsF e a
แน่นอนว่าการแทนที่ตัวแปรa
กับผลลัพธ์ของrecursionที่เราจะเรียกList e
เรามี
data List e = Nil | Cons e (List e)
algebraสำหรับfunctorแบบlistเลือกtypeแบบcarrierโดยเฉพาะและนิยามfunctionที่ทำการจับคู่รูปแบบ(Pattern matching)บนconstructorsทั้งสองทั้งสอง ค่าของมันสำหรับNillF
บอกเราในวิธีการที่จะประเมินlistว่างและค่าของมันสำหรับConsF
บอกเราในวิธีการรวมสมาชิกในตอนนี้กับค่าที่ถูกสะสมมาก่อนหน้านี้
ตัวอย่างเช่น ในที่นี้algebraสามารถถูกใช้ในการคำนวณขนาดของlist(ในtypeของcarrierคือInt
)
lenAlg :: ListF e Int -> Int
ConsF e n) = n + 1
lenAlg (NilF = 0 lenAlg
แน่นอนว่าcatamorphismมี่เป็นผลลัพธ์cata lenAlg
คำนวนขนาดของlist สังเกตว่าตัวประเมินนั้นคือผลรวมของ(1)functionที่นำสมาชิกของlistและตัวรวบรวม(accumulatorและreturnsตัวรวบรวมใหม่มา และ(2)ค่าเริมต้นในที่นี้คือเลขศูนย์ typeของค่านี้และtypeของตัวรวบรวมนั้นถูกให้มาโดยtypeของcarrier
เทียบสิ่งนี้กับนิยามแบบทั่วไปในHaskell
length = foldr (\e n -> n + 1) 0
ทั้สองargumentsสำหรับfoldr
นั้นคือสองส่วนประกอบของalgebraจริงๆ
เรามาลองอีกตัวอย่างหนึ่ง
sumAlg :: ListF Double Double -> Double
ConsF e s) = e + s
sumAlg (NilF = 0.0 sumAlg
ในอีกครั้งเราที่เราเทียบกับ
sum = foldr (\e s -> e + s) 0.0
คุณก็ได้เห็นแล้วว่าfoldr
นั้นคือแค่ทางเฉพาะของcatamorphismต่อlists
25.6 Coalgebras
เหมือกับทั่วๆไปเรามีการสร้างที่เป็นdualที่คือF-coalgebraที่ทิศทางของmorphismนั้นตรงกันข้าม
Coalgebrasสำหรับfunctorที่ให้มาก็ก่อให้เกิดcategoryที่homomorphismsทำการคงโครงสร้างทางcoalgebraเอาไว้ วัตถุสุดท้าย
ในcoalgebraสุดท้ายคือจุดคงที่ของfunctorในความหมายที่ว่าmorphism
coalgebraสุดท้ายนั้นมักจะถูกตีความในการเขียนโปรแกรมในฐานะวิธีการของการสร้าง(ที่อาจจะไม่มีที่สิ้นสุด)data structureหรือระบบของการเปลี่ยนแปลง(transition systems)
เหมือนกับcatamorphismที่สามารถถูกใช้ในการประเมินalgebraเริ่มต้น anamorphismสามารถถูกใช้ในการcoevaluate coalgebraสุดท้าย
ana :: Functor f => (a -> f a) -> a -> Fix f
= Fix . fmap (ana coalg) . coalg ana coalg
ตัวอย่างที่ตรงไปตรงมาของcoalgebraนั้นตามมาจากfunctorที่จุดคงที่นั้นคือstreamที่ไม่มีที่สิ้นสุดของสมาชิกของtype สิ่งนี้คือfunctor
data StreamF e a = StreamF e a
deriving Functor
และสิ่งนี้คือจุดคงที่ของมัน
data Stream e = Stream e (Stream e)
coalgebraสำหรับStreamF e
นั้นนำจุดเกิดของtypea
และสร้างpair(StreamF
นั้นเป็นชื่อที่อลังการของpair)ที่ประกอบด้วยสมาชิกหนึ่งและจุดเกิดอันต่อไป
คุณสามารถสร้างตัวอย่างง่ายๆของcoalgebrasที่สร้างsequencesไม่มีที่สิ้นสุดเหมือนกับlistของตัวเลขกำลังสองหรือreciprocals
ตัวอย่างที่น่าสนใจมากกว่าคือcoalgebraที่สร้างlistของจำนวนเฉพาะ เคล็ดลับคือการใช้listที่ไม่มีที่สิ้นสุดในฐานะcarrier จุดเกิดเริ่มต้นก็จะเป็นlistของ[2..]
จุดเกิดอันต่อไปก็จะเป็นส่วนหางของlistนั้นที่เลขที่หารสองลงตัวถูกนำออกไป มันคือlistของเลขคี่ที่เริ่มด้วย
era :: [Int] -> StreamF Int [Int]
: ns) = StreamF p (filter (notdiv p) ns)
era (p where notdiv p n = n `mod` p /= 0
anamorphismสำหรับcoalgebraนี้สร้างlistของprimesว่า
= ana era [2..] primes
streamนั้นคือlistที่ไม่มีที่สิ้นสุด ดังนั้นมันอาจจะเป็นไปได้ในการแปลงมันไปยังlistของHaskell ในการทำแบบนั้นเราสามารถใช้functorเดิมอย่างStreamF
ในการสร้างalgebraและเราสามารถดำเนินการทำcatamorphismข้างบนมัน ตัวอย่างเช่นนี้คือcatamorphismที่แปลงstreamไปยังlist
toListC :: Fix (StreamF e) -> [e]
= cata al
toListC where al :: StreamF e [e] -> [e]
StreamF e a) = e : a al (
ในที่นี้จุดคงที่ของเดิมนั้นเป็นทั้งalgebraเริ่มต้นและcoalgebraสุดท้ายสำหรับendofunctorเดียวกัน มันไม่เป็นแบบนี้ตลอดในcategoryทั่วๆไป โดยทั่วไปแล้วendofunctorอาจจะมีหลายจุดคงที่(หรือไม่มีเลย) algebraเริ่มต้นคือสิ่งที่เรียกว่าจุดคงที่ที่น้อยที่สุดและcoalgebraสุดท้ายคือจุดคงที่ที่สูงที่สุด แต่ในHaskellทั้งสองนั้นถูกนิยามโดยสูตรเดียวกันและพวกมันนั้นตรงกัน
anamorphismสำหรับlistsนั้นถูกเรียกว่าunfold ในการสร้างlistsที่คงที่ functorนั้นถูกแปลงในการสร้างpairของMaybe
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
ค่าของNothing
จะจบการสร้างของlist
ในกรณีที่น่าสนใจของcoalgebraนั้นเกี่ยวกับlenses lensสามารถถูกแสดงในฐานะคู่ของgetterและsetter
set :: a -> s -> a
get :: a -> s
ในที่นี้a
นั้นมักจะคือบางtypeแบบข้อมูลแบบproductกับfieldของtypes
getterดึงค่าของfieldนั้นและsetterแทนที่fieldนี้กับค่าใหม่ functionsทั้งสองเหล่านี้สามารถถูกรวมกันไปยังหนึ่งตัว
-> (s, s -> a) a
เราสามารถเขียนfunctionนี้ใหม่เพิ่มเติมว่า
-> Store s a a
ที่เราได้นิยามfunctor
data Store s a = Store (s -> a) s
สังเกตว่านี้นั้นไม่ใช่functorแบบalgebraicง่ายๆที่สร้างมาจากsumsของproducts มันข้องเกี่ยวกับexponential
lensคือcoalgebraสสำหรับfunctorนี้ที่มีtypeแบบcarriera
เราได้เห็นก่อนหน้านี้ว่าStore s
นั้นก็เป็นcomonad มันกลับมาเป็นว่าlensที่ประพฤติตนดีจะตรงกันกับcoalgebraที่เข้ากันได้กับโครงสร้างของcomonad เราจะมาพูดเกี่ยวกับสิ่งนี้ในบทต่อไป
25.7 โจทย์ท้าทาย
- ลองเขียนfunctionที่ทำการประเมินสำหรับringของpolynomialsที่มีตัวแปลเดียว คุณสามารถแสดงpolynomialในฐานะlistของcoefficientsที่อยู่ข้างหน้า การยกกำลังของ
ตัวอย่างเช่น อาจจะถูกแสดงในฐานะ (เริ่มมากับตัวยกกำลังศูนย์)อย่าง[-1, 0, 4]
- ลองgeneralizeการสร้างก่อนหน้านี้ไปยังpolynomialsสำหรับตัวแปลที่เป็นอิสระอย่าง
- ลองเขียนalgebraleสำหรับringของmatrices
- นิยามcoalgebraที่anamorphismสร้างlistของกำลังสองของจำนวนธรรมชาติ
- ใช้
unfoldr
ในการสร้างlistของจำนวนเฉพาะ ตัวแรก
(Page 272)