2010-12-10 74 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