2010-12-10 82 views
1

我經常對函數是這樣的:模式隱藏功能

fooInner :: Int -> Int -> [Int] -> [Int] 
fooInner 0 base accum = accum 
fooInner num base accum = fooInner c base ([r] ++ accum) 
        where .... 

foo :: Int -> Int -> [Int] 
foo a b = numNotationInner a b [] 

我創建「富」更舒適的使用功能。而不是fooInner 10 4 []我可以用foo 10 4.

有沒有什麼辦法可以'隱藏'foo內的foo來限制它的範圍?

回答

9

在這種情況下,你可以只隱藏在where塊膽量:

foo :: Int -> Int -> [Int] 
foo a b = fooInner a b [] where 
    fooInner :: Int -> Int -> [Int] -> [Int] 
    fooInner 0 base accum = accum 
    fooInner num base accum = fooInner c base ([r] ++ accum) 
     where ... 

雖然有,你可能會遇到這樣一對夫婦的問題:

  • 如果實現了多個where塊將只適用於其中之一:

    foo :: Int -> Int -> [Int] 
    foo 0 b = fooInner 1 b [] -- fooInner not in scope 
    foo a b = fooInner a b [] where 
        ... define fooInner ... 
    

    除非Haskell有一些語法功能,我不知道,你就必須做這樣的事情,如果你仍然想模式匹配:

    foo a b = case (a, b) of 
           (0, b) -> fooInner 1 b [] 
           (a, b) -> fooInner a b [] 
        where 
         ... define fooInner ... 
    

    我沒有測試這一點。您可能需要修補空白以擺脫語法錯誤。

  • 如果你的函數具有多態類型,你可能會遇到麻煩試圖將一個類型簽名添加到內部功能:

    foo :: (a -> a) -> a -> [a] 
    foo f z = loop z where 
        -- loop :: a -> [a] -- causes a type error 
        loop z = z : loop (f z) 
    

    與類型簽名loop :: a -> [a]的問題是,在它的背景下,並不真正適用於全部a,只是a對應於傳遞給foo的參數。因爲它使用的是f,所以類型綁定到a,這意味着它不能再適用於任何a

    這裏的簡單解決方案是不使用類型簽名。但是,如果你真的想要甚至需要一個類型簽名,但在錯誤類型加一個結果,使ScopedTypeVariables延伸,並做到這一點:

    foo :: forall a. (a -> a) -> a -> [a] 
    foo f z = loop z where 
        loop :: a -> [a] 
        loop z = z : loop (f z) 
    

    forall延伸的a超出其原始類型的簽名範圍以涵蓋實施中出現的任何類型簽名。這意味着在loop :: a -> [a],afoo的簽名中綁定了a

+0

感謝您的支持 – demas 2010-12-10 09:22:44