3

型を使用してインスタンスを明確にするコードがいくつかあり(実際のコードは型タグにGHC.TypeLitsシングルトンを使用していますが、それは密接な関係はないと思います)、テキストレベルの重複を避けるためにletバインディングを使用したいと思います; 残念ながら、これは結果を単形化します。

以下は問題の例です。

class Foo a where
  foo :: a

instance Foo Int where
  foo = 0

instance Foo Char where
  foo = 'a'

data Bar a = Bar String
  deriving (Show)

bar :: forall a. (Show a, Foo a) => a -> Bar a
bar _ = Bar $ show (foo :: a)

idInt :: Bar Int -> Bar Int
idInt = id

idChar :: Bar Char -> Bar Char
idChar = id

main = let quux = bar undefined in
  print (idInt quux) >> print (idChar quux)

上記のコードはコンパイルされません(ただし、もちろん、多形であるように注釈を入力すると、すべてが正常に機能します)、と一致しquuxなかったと正しく文句を言います。タイプアノテーションを付けずに、また各使用サイトで繰り返すことなく、コンパイルを成功させる方法はありますか?IntCharbar undefined

4

1 に答える 1

6
{-# LANGUAGE NoMonomorphismRestriction #-}

または、よりグローバルでないものが必要な場合

let quux () = bar undefined in 
    print (idInt (quux ()) >> print (idChar (quux ()))

後者が機能する理由は、バインディングが等号の左側に引数がない場合にのみ単形化されるためです。

let foo = \x y -> x + y   -- :: Integer -> Integer -> Integer
let bar x y = x + y       -- :: (Num a) => a -> a -> a

したがって、quux単形化しないようにするには、等号の左側に引数を指定する必要があります。quuxが値ではなく関数の場合は、単純にetaを展開して、同じ効果を得ることができます。

let quux x = bar undefined x in ...

前者の場合、パフォーマンスについて心配する必要はありません。常にと呼ぶとquux ()、インライン化され、明示的な型署名を持つバージョンと同じコードが生成されます。

于 2013-02-02T01:14:51.677 に答える