4

これは恐ろしく不自然な例ですが、とにかく...これは型チェックを行います:

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> let foo0 = foo (Bar id) (\n -> [n, n*2])
GHCi> map (runFoo $ runBar foo0 4) [1..10]
[False,False,False,True,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が、明らかにそうではありません。これには特定の理由がありますか?ネストされた s で機能しないのは意図的なwhereものですか?これが同等の実際の問題で発生した場合、どのような回避策がありますか?

4

1 に答える 1

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スコープに持ち込まれます。

于 2012-08-29T10:41:08.330 に答える