ScopedTypeVariables无法使用嵌套的where子句?

时间:2012-08-29 10:36:45

标签: haskell type-variables

这是一个可怕的人为例子,但无论如何......这个样子:

newtype Foo c = Foo { runFoo :: c -> Bool }
newtype Bar c = Bar { runBar :: Int -> c }

foo :: Eq c => Bar c -> (c -> [c]) -> Bar (Foo c)
foo bar f = Bar res
 where res n = Foo judge
        where judge c = (c`elem`) . f $ runBar bar n

并且工作

  

GHCI>让foo0 = foo(条形码)(\ n - > [n,n * 2])
  GHCI> map(runFoo $ runBar foo0 4)​​[1..10]
  [FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE]

但如果我将明显的类型签名添加到本地函数judge

foo :: Eq c => Bar c -> (c -> [c]) -> Bar (Foo c)
foo bar f = Bar res
 where res n = Foo judge
        where judge :: c -> Bool
              judge c = (c`elem`) . f $ runBar bar n

它以

失败
Could not deduce (c ~ c2)
from the context (Eq c)
  bound by the type signature for
             foo :: Eq c => Bar c -> (c -> [c]) -> Bar (Foo c)

等等。在Haskell 98中几乎没有什么意外,但我认为ScopedTypeVariables应该允许编写这样的签名,但显然它不会。是否有一个特定的原因,是否故意它不适用于嵌套的where,如果在可比较的真实单词问题中出现了什么变通方法呢?

1 个答案:

答案 0 :(得分:8)

显然您忘记将类型变量c带入显式forall的范围,

{-# LANGUAGE ScopedTypeVariables #-}
module Foobar where

newtype Foo c = Foo { runFoo :: c -> Bool }
newtype Bar c = Bar { runBar :: Int -> c }

foo :: forall c. Eq c => Bar c -> (c -> [c]) -> Bar (Foo c)
foo bar f = Bar res
 where res n = Foo judge
        where judge :: c -> Bool
              judge c = (c`elem`) . f $ runBar bar n

编译好。

ScopedTypeVariables本身不会将签名中的类型变量带入范围,只有具有明确forall的变量才会进入范围。