ในปัญหาการเรียนรู้ที่ฉันทำไปด้วยฉันรู้ว่าฉันต้องการประเภทของฟังก์ชันที่มีการใช้งานการเขียนเป็นต้นเหตุผล ...
มันจะสะดวกในการปฏิบัติต่อการเป็นตัวแทนของฟังก์ชั่นราวกับว่ามันเป็นฟังก์ชั่นของตัวเองเพื่อให้การใช้ฟังก์ชั่นโดยนัยใช้ล่ามและฟังก์ชั่นการแต่งได้คำอธิบายใหม่
เมื่อคุณมี typeclass สำหรับฟังก์ชั่นคุณสามารถได้รับ typeclass สำหรับฟังก์ชั่นพิเศษ - ในกรณีของฉันฉันต้องการฟังก์ชั่นกลับด้าน
ตัวอย่างเช่นฟังก์ชั่นที่ใช้การชดเชยจำนวนเต็มอาจแสดงโดย ADT ที่มีจำนวนเต็ม การใช้ฟังก์ชั่นเหล่านั้นหมายถึงการเพิ่มจำนวนเต็ม องค์ประกอบถูกนำมาใช้โดยการเพิ่มจำนวนเต็มห่อ ฟังก์ชันผกผันมีจำนวนเต็มค่าเป็นลบ ฟังก์ชั่นเอกลักษณ์ห่อศูนย์ ไม่สามารถจัดหาฟังก์ชั่นคงที่ได้เนื่องจากไม่มีตัวแทนที่เหมาะสมสำหรับมัน
แน่นอนว่ามันไม่จำเป็นต้องสะกดสิ่งต่าง ๆ ราวกับว่ามันเป็นค่าของฟังก์ชั่น Haskell ของแท้ แต่เมื่อฉันมีความคิดฉันคิดว่าห้องสมุดแบบนั้นต้องมีอยู่แล้วและอาจใช้การสะกดมาตรฐาน แต่ฉันไม่สามารถหาประเภทของงานพิมพ์ในห้องสมุด Haskell ได้
ฉันพบโมดูลData.Functionแต่ไม่มีประเภทของงานพิมพ์ - มีเพียงฟังก์ชันทั่วไปบางส่วนที่มีให้จาก Prelude
ดังนั้น - ทำไมไม่มี typeclass สำหรับฟังก์ชั่น? เป็น "เพียงเพราะไม่มี" หรือ "เพราะไม่มีประโยชน์อย่างที่คุณคิด" หรืออาจมีปัญหาพื้นฐานกับความคิด?
ปัญหาที่เป็นไปได้ที่ใหญ่ที่สุดที่ฉันเคยคิดมาก่อนก็คือฟังก์ชั่นแอปพลิเคชั่นในฟังก์ชั่นที่เกิดขึ้นจริงอาจจะต้องได้รับการใส่รหัสเป็นพิเศษโดยคอมไพเลอร์เพื่อหลีกเลี่ยงปัญหาการวนซ้ำ และเพื่อที่ฉันจะต้องเรียกใช้ฟังก์ชั่นแอปพลิเคชั่นและเพื่อที่จะทำ ...
เบาะแสเพิ่มเติม
โค้ดตัวอย่างเพื่อแสดงสิ่งที่ฉันตั้งใจจะ ...
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
-- In my first version, Doable only had the one argument f. This version
-- seemed to be needed to support the UndoableOffset type.
--
-- It seems to work, but it also seems strange. In particular,
-- the composition function - a and b are in the class, but c isn't,
-- yet there's nothing special about c compared with a and b.
class Doable f a b where
fwdApply :: f a b -> a -> b
compDoable :: f b c -> f a b -> f a c
-- In the first version, I only needed a constraint for
-- Doable f a b, but either version makes sense.
class (Doable f a b, Doable f b a) => Undoable f a b where
bwd :: f a b -> f b a
bwdApply :: f a b -> b -> a
bwdApply f b = fwdApply (bwd f) b
-- Original ADT - just making sure I could wrap a pair of functions
-- and there were no really daft mistakes.
data UndoableFn a b = UFN { getFwd :: a -> b, getBwd :: b -> a }
instance Doable UndoableFn a b where
fwdApply = getFwd
compDoable f g = UFN ((getFwd f) . (getFwd g)) ((getBwd g) . (getBwd f))
instance Undoable UndoableFn a b where
bwd f = UFN (getBwd f) (getFwd f)
bwdApply = getBwd
-- Making this one work led to all the extensions. This representation
-- can only represent certain functions. I seem to need the typeclass
-- arguments, but also to need to restrict which cases can happen, hence
-- the GADT. A GADT with only one constructor still seems odd. Perhaps
-- surprisingly, this type isn't just a toy (except that the whole thing's
-- a toy really) - it's one real case I need for the exercise. Still a
-- simple special case though.
data UndoableOffset a b where
UOFF :: Int -> UndoableOffset Int Int
instance Doable UndoableOffset Int Int where
fwdApply (UOFF x) y = y+x
compDoable (UOFF x) (UOFF y) = UOFF (x+y)
instance Undoable UndoableOffset Int Int where
bwdApply (UOFF x) y = y-x
bwd (UOFF x) = UOFF (-x)
-- Some value-constructing functions
-- (-x) isn't shorthand for subtraction - whoops.
undoableAdd :: Int -> UndoableFn Int Int
undoableAdd x = UFN (+x) (\y -> y-x)
undoableMul :: Int -> UndoableFn Int Int
undoableMul x = UFN (*x) (`div` x)
-- With UndoableFn, it's possible to define an invertible function
-- that isn't invertible - to break the laws. To prevent that, need
-- the UFN constructor to be private (and all public ops to preserve
-- the laws). undoableMul is already not always invertible.
validate :: Undoable f a b => Eq a => f a b -> a -> Bool
validate f x = (bwdApply f (fwdApply f x)) == x
-- Validating a multiply-by-zero invertible function shows the flaw
-- in the validate-function plan. Must try harder.
main = do putStrLn . show $ validate (undoableAdd 3) 5
putStrLn . show $ validate (undoableMul 3) 5
--putStrLn . show $ validate (undoableMul 0) 5
fb1 <- return $ UOFF 5
fb2 <- return $ UOFF 7
fb3 <- return $ compDoable fb1 fb2
putStrLn $ "fwdApply fb1 3 = " ++ (show $ fwdApply fb1 3)
putStrLn $ "bwdApply fb1 8 = " ++ (show $ bwdApply fb1 8)
putStrLn $ "fwdApply fb3 2 = " ++ (show $ fwdApply fb3 2)
putStrLn $ "bwdApply fb3 14 = " ++ (show $ bwdApply fb3 14)
โปรแกรมประยุกต์ที่เกี่ยวข้องกับชนิดของการรวมกันที่ค่าแบบครบวงจรจะไม่เท่ากัน แต่มีความสัมพันธ์ผ่านฟังก์ชั่นผกผันเหล่านั้น - ตรรกะเปิดฉากสไตล์ แต่มีa = f(b)
ข้อ จำกัด a = b
มากกว่า องค์ประกอบส่วนใหญ่จะเป็นผลมาจากการปรับโครงสร้างการค้นหาแบบรวม ความจำเป็นในการผกผันควรชัดเจน
หากไม่มีรายการในชุดรวมมีค่าที่แน่นอนแล้วรายการเฉพาะสามารถวัดปริมาณได้เมื่อเทียบกับรายการอื่นในชุดรวม นั่นเป็นเหตุผลที่ฉันไม่ต้องการใช้ฟังก์ชั่น "ของจริง" - คำนวณค่าสัมพัทธ์เหล่านั้น ฉันสามารถวางฟังก์ชั่นทั้งหมดและมีปริมาณสัมบูรณ์และสัมพัทธ์ - ฉันอาจต้องการเพียงตัวเลข / เวกเตอร์และ(+)
- แต่นักบินอวกาศสถาปัตยกรรมภายในของฉันต้องการความสนุกของเขา
วิธีเดียวที่ฉันจะแยกลิงค์ออกจากกันอีกครั้งก็คือการย้อนรอยและทุกอย่างบริสุทธิ์ - สหภาพ - การค้นหาจะทำโดยใช้กุญแจIntMap
เป็น "ตัวชี้" ฉันมีสหภาพหางานง่าย ๆ แต่เมื่อฉันยังไม่ได้เพิ่มฟังก์ชั่นที่กลับด้านได้ไม่มีจุดที่แสดงไว้ที่นี่
เหตุผลที่ฉันไม่สามารถใช้ Applicative, Monad, Arrow เป็นต้น
การดำเนินการหลักที่ฉันต้องการคลาส abstraction ของฟังก์ชันเพื่อจัดเตรียมคือแอ็พพลิเคชันและองค์ประกอบ ว่าเสียงที่คุ้นเคย - เช่นApplicative
(<*>)
, Monad
(>>=)
และArrow
(>>>)
มีฟังก์ชั่นทุกองค์ประกอบ อย่างไรก็ตามประเภทที่ใช้ฟังก์ชั่นนามธรรมในกรณีของฉันจะมีโครงสร้างข้อมูลบางอย่างที่แสดงถึงฟังก์ชั่น แต่ที่ไม่ได้ (และไม่สามารถมี) ฟังก์ชั่นและที่สามารถเป็นตัวแทนของชุด จำกัด ฟังก์ชั่นบางอย่าง
ดังที่ฉันได้กล่าวถึงในคำอธิบายของรหัสบางครั้งฉันสามารถหาจำนวนไอเท็มที่สัมพันธ์กับรายการอื่นเท่านั้นเนื่องจากไม่มีรายการในคลัสเตอร์ "รวม" ที่มีค่าที่แน่นอน ฉันต้องการที่จะได้รับการเป็นตัวแทนของฟังก์ชั่นนั้นซึ่งโดยทั่วไปจะเป็นองค์ประกอบของฟังก์ชั่นที่มีให้หลาย (เดินขึ้นไปที่บรรพบุรุษร่วมกันในยูเนี่ยน / หาต้นไม้) และฟังก์ชั่นอินเวอร์ส สิ่งของ).
กรณีง่าย - ที่ "ฟังก์ชั่น" ดั้งเดิมถูก จำกัด เพียงจำนวนเต็ม "ฟังก์ชั่น" ฉันต้องการผลประกอบการเป็นฟังก์ชั่น "จำนวนเต็มชดเชย" - เพิ่มองค์ประกอบ offsets นั่นเป็นส่วนสำคัญที่ว่าทำไมฟังก์ชั่นการแต่งเพลงจึงต้องอยู่ในคลาสเช่นเดียวกับแอปพลิเคชันฟังก์ชั่น
ซึ่งหมายความว่าฉันไม่สามารถให้การดำเนินงานpure
, return
หรือarr
ประเภทของฉันดังนั้นฉันไม่สามารถใช้Applicative
, หรือMonad
Arrow
นี่ไม่ใช่ความล้มเหลวของประเภทเหล่านี้ - มันเป็นสิ่งที่ไม่เข้ากับแนวนามธรรม สิ่งที่เป็นนามธรรมที่ฉันต้องการนั้นเป็นฟังก์ชั่นบริสุทธิ์ที่เรียบง่าย ไม่มีผลข้างเคียงตัวอย่างเช่นและไม่จำเป็นต้องสร้างสัญกรณ์ที่สะดวกสำหรับการจัดลำดับและการเขียนฟังก์ชั่นอื่นที่ไม่ใช่เทียบเท่าของมาตรฐาน (.) ที่ใช้กับทุกฟังก์ชั่น
ฉันจะทำได้Category
เช่น ฉันมั่นใจว่าทุกฟังก์ชั่นการใช้งานของฉันจะสามารถระบุตัวตนได้แม้ว่าฉันอาจไม่ต้องการมันก็ตาม แต่เนื่องจากCategory
ไม่รองรับแอปพลิเคชันฉันยังต้องการคลาสที่ได้รับมาเพื่อเพิ่มการดำเนินการนั้น
Applicative
มันค่อนข้างถูกต้อง - มันต้องการค่าที่จะห่อรวมทั้งฟังก์ชั่นในขณะที่ฉันเพียงต้องการห่อฟังก์ชั่นและฟังก์ชั่นห่อเป็นจริงฟังก์ชั่นในขณะที่ฟังก์ชั่นห่อของฉันจะไม่ กรณีทั่วไปส่วนใหญ่เป็น AST ที่อธิบายฟังก์ชัน) <*>
มีประเภทอยู่ที่ไหนf (a -> b) -> f a -> f b
ฉันต้องการผู้ให้บริการแอปพลิเคชั่นที่มีประเภทg a b -> a -> b
ที่ไหนa
และb
ระบุโดเมนและโคโดเมนของฟังก์ชั่นที่ถูกห่อไว้ แต่สิ่งที่อยู่ภายใน wrapper ไม่ได้เป็นฟังก์ชันจริง (จำเป็น) On Arrows - อาจเป็นไปได้ที่ฉันจะดู