2012-02-12 71 views
9

爲什麼Haskell需要多個重寫規則,具體取決於函數組合技術和長度?有沒有辦法避免這種情況?Haskell重寫規則和函數組合

例如,假設下面的代碼...

{-# RULES 
"f/f" forall a. f (f a) = 4*a 
    #-} 
f a = 2 * a 

這個工程的

test1 = f (f 1) 

但是我們需要添加一個規則

test2 = f . f $ 1 

test3 = f $ f 1 

留給我們的規則如下

{-# RULES 
"f/f1" forall a. f (f a) = 4 * a 
"f/f2" forall a. f . f $ a = 4 * a 
"f/f3" forall a. f $ f $ a = 4 * a 
    #-} 

然而,當我們這些串在一起,或使用一些其他形式的組成規則不火。

test4 = f . f . f $ 1 
test5 = f $ f $ f $ 1 
test6 = f $ 1 

這是爲什麼?我是否必須爲每個可能的實現編寫重寫規則?

+1

我其實不知道,但我猜這是因爲重寫規則不適用於你導入的函數。 ''''和'.'只是從Prelude導入的函數。 – 2012-02-12 23:40:36

回答

13

的規則,因爲規則有機會解僱前的很簡單的功能f內聯不火的情況較多。如果延遲內聯,

{-# INLINE [1] f #-} 

規則

{-# RULES "f/f" forall a. f (f a) = 4*a #-} 

應該火所有這些情況(7.2.2和7.4.1這裏工作)。

原因是規則匹配器不是過分詳細的,它只匹配具有規則語法形式的表達式(不完全正確,規則體也經歷一些規範化)。表達式f $ f 3f . f $ 4與規則的語法形式不匹配。要匹配規則,必須進行一些重寫,($)(.)必須在規則匹配表達式之前內聯。但是,如果不阻止f在簡化程序的第一階段中被內聯,則它會在同一運行中被其主體取代,因爲內聯了($)(.),所以在下一次迭代中,簡化程序不再看到f,它只看到2*(2*x),這與規則不匹配。

3

我本來以爲這會在默認情況下工作,但你可以添加兩個重寫規則,使./$降低到lambda表達式/應用程序,因此,這將總是匹配:

{-# RULES 
"f/f" forall a. f (f a) = 4*a 

"app" forall f x. f $ x = f x 
"comp" forall f g. f . g = (\x -> f (g x)) 
    #-} 

f a = 3 * a -- make this 3*a so can see the difference 

測試:

main = do 
    print (f . f $ 1) 
    print (f (f 1)) 
    print (f $ f 1) 
    print (f $ f $ 1) 
    print (f $ f $ f $ f $ 1) 
    print (f . f . f . f $ 1) 
    print (f $ f $ f $ 1) 
    print (f . f . f $ 1) 
    print (f $ 1) 

輸出:

4 
4 
4 
4 
16 
16 
12 
12 
3 

這也將在一定的工作(但不是全部)比較晦澀ç由於其他重寫規則,例如,所有的這些都可以工作:

mapf x = map f $ map f $ [x] 
mapf' x = map (f.f) $ [x] 
mapf'' x = map (\x -> f (f x)) $ [x]