7

(ひどく不自然な例を許してください)

私がやりたいのは、where句でタイプを指定することです。

somemap :: (a -> b) -> [a] -> [b]
somemap f xs = ys
  where
    some = take 5 xs :: [a]
    ys = map f some :: [b]

しかし、これはエラーを引き起こします:

*Main> :load file.hs 
[1 of 1] Compiling Main             ( file.hs, interpreted )

fil.hs:15:18:
    Couldn't match expected type `a1' against inferred type `a'
      `a1' is a rigid type variable bound by
           an expression type signature at file.hs:15:25
      `a' is a rigid type variable bound by
          the type signature for `somemap' at file.hs:12:12
      Expected type: [a1]
      Inferred type: [a]
    In the second argument of `take', namely `xs'
    In the expression: take 5 xs :: [a]

file.hs:16:13:
    Couldn't match expected type `b1' against inferred type `b'
      `b1' is a rigid type variable bound by
           an expression type signature at file.hs:16:24
      `b' is a rigid type variable bound by
          the type signature for `somemap' at file.hs:12:17
    In the first argument of `map', namely `f'
    In the expression: map f some :: [b]
    In the definition of `ys': ys = map f some :: [b]
Failed, modules loaded: none.

一方、具体的なタイプを指定し、とを置き換えIntても問題ありません。aBoolb

somemap :: (Int -> Bool) -> [Int] -> [Bool]
somemap f xs = ys
  where
    some = take 5 xs :: [Int]
    ys = map f some :: [Bool]

だから私の質問は:where句でジェネリック型と型制約を指定するにはどうすればよいですか?

4

1 に答える 1

15

where節の中では、型変数ab新しい型変数です。型変数はスコープされていないため、すべての型シグネチャには、トップレベルで定義されているかのように、新しい型変数が提供されます。

ScopedTypeVariables拡張機能をオンにして({-# LANGUAGE ScopedTypeVariables #-}ファイルの先頭に配置)、somemapの型宣言を次のように変更した場合:

somemap :: forall a b. (a -> b) -> [a] -> [b]

そうすれば、指定したwhere句の定義が正しく機能します。forallsは下位互換性のためにのみ必要であると思います。そのためwhere、ポリモーフィック値の句で型変数を再利用するコードは壊れません。

拡張機能を使用したくない場合は、のような醜いヘルパー関数を定義して型を統一することもできますasTypeOf

于 2012-05-03T15:18:51.933 に答える