开发者

pattern to hide function

I often have pair of functions like this:

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 []

I have created 'foo' to more comfortable use of function. Instead of fooInner 10 4 [] I can use foo 10 4.

Is there any way to 'hide' fooInner inside foo to limit its scope?


In this case, you could just hide the guts in a where block:

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 ...

Though there are a couple issues you might encounter doing this:

  • If the implementation has multiple patterns, the where block will only apply to one of them:

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

    Unless Haskell has some syntactic feature I don't know about, you'll have to do something like this if you still want to pattern match:

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

    I didn't test this. You might have to tinker with the whitespace to get rid of syntax errors.

  • If your function has polymorphic types, you may run into trouble trying to add a type signature to the inner function:

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

    The problem with the type signature loop :: a -> [a] is that, in its context, it doesn't truly work for all a, just the a corresponding to the arguments passed to foo. Because it's using f, the type is bound to that a, meaning it can no longer work for any a.

    The simple solution here is to not use a type signature. However, if you really want or even need a type signature, but adding one results in a type error, enable the ScopedTypeVariables extension, and do this:

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

    The forall extends the scope of a beyond its originating type signature to cover any type signatures appearing in the implementation. This means that in loop :: a -> [a], a is bound to the a in foo's signature.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜