我試圖將下面的haskell代碼轉換爲點自由樣式,但無濟於事。Haskell中的點自由問題
bar f g xs = filter f (map g xs)
我是新來的Haskell和任何幫助將是巨大的
我試圖將下面的haskell代碼轉換爲點自由樣式,但無濟於事。Haskell中的點自由問題
bar f g xs = filter f (map g xs)
我是新來的Haskell和任何幫助將是巨大的
轉換爲無點風格可以完全機械地完成,雖然很難理解Haskell語法的基本原理,如左關聯函數應用,x + y
與(+) x y
相同。我會假設你對Haskell語法很熟悉;如果沒有,我建議先閱讀LYAH的前幾章。
您需要以下組合器,它們位於標準庫中。我也從combinator演算中給出他們的標準名稱。
id :: a -> a -- I
const :: a -> b -> a -- K
(.) :: (b -> c) -> (a -> b) -> (a -> c) -- B
flip :: (a -> b -> c) -> (b -> a -> c) -- C
(<*>) :: (a -> b -> c) -> (a -> b) -> (a -> c) -- S
一次處理一個參數。將左側的參數移動到右側的lambdas,例如
f x y = Z
成爲
f = \x -> \y -> Z
我喜歡在一個時間,而不是所有做這一個參數一次,它只是看起來更清潔。
然後根據以下規則消除剛創建的lambda。我將用小寫字母表示文字變量,用大寫字母表示更復雜的表達式。
\x -> x
,更換id
\x -> A
,其中A
是在x
不會發生,與const A
\x -> A x
,其中x
不會發生任何表情在A
中,替換爲A
。這被稱爲「eta收縮」。\x -> A B
,然後
x
同時出現在A
和B
,更換(\x -> A) <*> (\x -> B)
。A
x
,與flip (\x -> A) B
B
x
,更換A . (\x -> B)
,x
沒有在任何A
或B
發生,那麼,還有我們應該用另一個規則已經。然後向內進行,省去您創建的lambda表達式。讓我們來看看這個例子:
f x y z = foo z (bar x y)
-- Move parameter to lambda:
f x y = \z -> foo z (bar x y)
-- Remember that application is left-associative, so this is the same as
f x y = \z -> (foo z) (bar x y)
-- z appears on the left and not on the right, use flip
f x y = flip (\z -> foo z) (bar x y)
-- Use rule (3)
f x y = flip foo (bar x y)
-- Next parameter
f x = \y -> flip foo (bar x y)
-- Application is left-associative
f x = \y -> (flip foo) (bar x y)
-- y occurs on the right but not the left, use (.)
f x = flip foo . (\y -> bar x y)
-- Use rule 3
f x = flip foo . bar x
-- Next parameter
f = \x -> flip foo . bar x
-- We need to rewrite this operator into normal application style
f = \x -> (.) (flip foo) (bar x)
-- Application is left-associative
f = \x -> ((.) (flip foo)) (bar x)
-- x appears on the right but not the left, use (.)
f = ((.) (flip foo)) . (\x -> bar x)
-- use rule (3)
f = ((.) (flip foo)) . bar
-- Redundant parentheses
f = (.) (flip foo) . bar
現在就去嘗試一下吧!決定使用哪種規則並沒有真正的巧妙:使用適用的任何規則,並且您將取得進展。
這是我第一次看到任何人發佈實際*算法*做這個。我知道必須有一個,但我不知道它是什麼...... – MathematicalOrchid
我見過幾本教科書,努力像您所做的那樣努力呈現轉換! (只是一個側面說明,最後一個表達式通常被視爲'(flip foo。).bar')。 –
作爲參考,我想補充說,這是(主要)[從lambda演算轉換成SK演算](https://en.wikipedia.org/wiki/Combinatory_logic#Conversion_of_a_lambda_term_to_an_equivalent_combinatorial_term)(以防萬一有人想谷歌更多關於它)。 – phg
我問lambdabot,誰各種Haskell的IRC頻道掛出一個機器人,自動計算出自由點等價的。該命令是@pl
(毫無意義的)。的bar
10:41 <frase> @pl bar f g xs = filter f (map g xs)
10:41 <lambdabot> bar = (. map) . (.) . filter
點免費版是:
bar = (. map) . (.) . filter
這比原始(非點免費)碼可以說少理解。在決定是否逐個使用無點式時,請使用您的判斷力。
最後,如果你不喜歡IRC也有基於Web的免費點 轉換器,例如Blunt(由@TaylorFausak),該pointfree
命令行程序,和其他工具。
如果你不想啓動一個IRC客戶端,我寫了一個web爲您完成這些轉換的服務。它叫Blunt:https://blunt.herokuapp.com/#input=bar%20f%20g%20xs%20%3D%20filter%20f%20(map%20g%20xs) –
@TaylorFausak謝謝,我將合併這個在我的答案中。 – frasertweedale
您也可以使用'cabal install pointfree'安裝命令行版本。如果你給它自己的ghci定義,你可以從ghci中使用它:) https://hackage.haskell.org/package/pointfree – Jxek
這兩個現有的答案都沒有真正以一種闡明的方式回答你的具體問題:一個是「這裏是規則,爲你自己工作」,另一個是「這裏是答案,沒有任何信息規則如何產生它。「
前三個步驟非常簡單,包括通過編寫h = f . g
從h x = f (g x)
的格式中刪除共同的x
。本質上,它在說:「如果你可以寫在表格a $ b $ c $ ... $ y $ z
的事情,你要刪除的z
,改變所有的美元,以點,a . b . c . ... . y
:
bar f g xs = filter f (map g xs)
= filter f $ (map g xs)
= filter f $ map g $ xs -- because a $ b $ c == a $ (b $ c).
bar f g = filter f . map g
= (filter f .) (map g)
= (filter f .) $ map $ g
bar f = (filter f .) . map
所以這最後f
是唯一棘手的部分,它的。棘手的,因爲f
是不是在表達的「終點」,但看着它,我們看到,這是適用於表達式的其餘部分的功能部(. map)
:
bar f = (.) (filter f) . map
bar f = (. map) $ (.) $ filter $ f
bar = (. map) . (.) . filter
,這就是你如何減小表達,當你沒有複雜的事情l其中出現ike f x x
等。通常有一個功能flip f x y = f y x
它「翻轉參數」;你總是可以使用它將f
移動到另一邊。如果您包含顯式翻轉呼叫,則我們有flip (.) map . (.) . filter
。
請注意,在某些情況下(如這樣),免費版本可能比原始代碼更不可讀。除非你瞄準混淆的代碼,否則請小心使用無點的風格。 – chi
'過濾器f。圖g =((。)。filter)f(map g)=((。map)。((。)。filter))fg' –