2012-01-19 56 views
17

我經常有這樣的模式的功能:哈斯克爾 - 模式匹配的語法糖和地方

f :: a -> b 
f x = case x of 
    ... -> g ... 
    ... -> g ... 
    ... 
    ... -> g ... 
    where g = ... 

沒有爲幾乎這種情況下的語法糖:

f :: a -> b 
f ... = g ... 
f ... = g ... 
... 
f ... = g ... 

不幸的是,我可以」不要把我的where附加到它上面:我顯然會得到一堆not in scope s。 我可以使g成爲一個單獨的函數,但這並不好:我的模塊的名稱空間將被實用程序函數污染。 有什麼解決方法嗎?

+4

您不必出口'g',因此命名空間的污染只是一個問題* *內自己的模塊。 –

回答

10

我認爲你的第一個例子並不糟糕。唯一的語法權重是case x of,加上->而不是=;後者由於可以省略每個子句的函數名稱而被抵消了。事實上,即使dflemstr提出的go輔助函數在語法上也較重。

不可否認,它與普通函數子句語法相比稍有不一致,但這可能是一件好事:它更直觀地界定了x可用的範圍。

+0

用於定義函數的等式語法看起來像是一種不必要的噱頭。 –

10

不,沒有解決方法。當你有這樣一個功能的多個子句時,他們不能共享一個where條款。你唯一的選擇是使用一個case語句,或做這樣的事情:

f x = 
    go x 
    where 
    go ... = g ... 
    go ... = g ... 
    g = ... 

...如果你真的使用函數形式,出於某種原因。

6
f = g . h -- h is most of your original f 
    where h ... = ... 
     h ... = ... 
     g = 
+0

我認爲OP正在尋找一個通用的解決方案,其中'g'可能出現在任何方程的RHS上的任何地方(或根本不存在)。 –

+1

是的,我覺得這個問題很模糊,給出了一個還沒有得到答案的答案。 – dave4420

3

您的原始解決方案似乎是最好的和唯一的解決方法。從語法上講,如果功能參數更輕,則不會比直接模式匹配更重。

但是,如果你需要的只是檢查先決條件而不是模式匹配,請不要忘記守衛,它允許你自由訪問where範圍。但我真的沒有看到你的case of解決方案沒有什麼不好。

f :: a -> b 
f a 
    | a == 2 = ... 
    | isThree a = ... 
    | a >= 4 = ... 
    | otherwise = ... 
    where isThree x = x == 3 
5

從2010年哈斯克爾上,或者用GHC你也可以這樣做:

f x 
    | m1 <- x = g 
    | m2 <- x = g 
    ... 
    where g = 

但請注意,您不能使用g的模式綁定的變量。這相當於:

f x = let g = ... in case() of 
    () -> case x of 
      m1 -> g 
      _ -> case x of 
       m2 -> g 
       .... 
1

它是安全的假設你一直使用的最g,如果不是全部,case語句的不同分支的?

在假設f :: a -> b一些ab(可能多晶型),g是一定形式c -> d,這意味着有必須是一種方法,持續提取ca的一些功能操作。打電話給getC :: a -> c。在這種情況下,解決方案將僅針對所有情況使用h . g . getC,其中h :: d -> b

但是,假設你不能總是從a得到c。也許a的形式是f c,其中fFunctor?然後你可以fmap g :: f c -> f d,然後以某種方式將f d轉換成b

只是在這裏漫步,但fmap是當我看到你似乎在每個分支上應用g時想到的第一件事。

0

隨着LambdaCase,你也可以這樣做:

{-# language LambdaCase #-} 

f :: a -> b 
f = \case 
    ... -> g ... 
    ... -> g ... 
    ... 
    ... -> g ... 
    where g = ...