2012-02-05 4 views
5

先ほど、行列の数値を集める小さなプログラムを作成しました - data Matrix = Matrix [[Int]]角で始まり - [Direction]すべてその後、私はこの機能を使用LeftUpRighthaskellの多型 - 異なる名前を付けずに関数の複数のバージョンを使用する

turnLUR :: Transformable a => (Corner, Direction) -> a -> a 

に - の3つのタイプが、私は与えられたコーナーと方向を回転させる変換関数を生成する機能を有するクラスTransformable

のインスタンスであります「収穫」マトリックス内のすべての番号に:

harvest :: Matrix → [(Corner,Direction)] → [Int] 
harvest _ [] = [] 
harvest (Matrix []) _ = [] 
harvest as (cd:csds) = b ++ harvest (Matrix bs) csds' --cd = (Corner,Direction) 
        where f1 = turnLUR cd -- Matrix -> Matrix 
          f2 = turnLUR cd -- Corner -> Corner 
          f3 = turnLUR cd -- Direction -> Direction 
          Matrix (b:bs) = f1 as -- b = first line of [[Int]] 
          fcfd (c,d) = (f2 c,f3 d) 
          csds' = map fcfd csds 

今私は f1f2f3代わりに一つの機能を使用するので書き留めなければならないのですなぜ、私の質問 f 3回(!私の心の中でDRYに保ちます) - Corners, Directions、および Matrixの3種類すべてが class Transformableのインスタンスです。

「同じ」機能の3つのバージョンを作成することなく、そのコードをどのように書くことができますか?

答えて

11

これはmonomorphism restrictionが原因です。それを明示的な型シグネチャを与え、あなたは毎回同じ機能を再利用できるようになります:

また
harvest :: Matrix → [(Corner,Direction)] → [Int] 
harvest _ [] = [] 
harvest (Matrix []) _ = [] 
harvest as (cd:csds) = b ++ harvest (Matrix bs) csds' --cd = (Corner,Direction) 
        where f :: Transformable a => a -> a 
          f = turnLUR cd 
          Matrix (b:bs) = f as -- b = first line of [[Int]] 
          fcfd (c,d) = (f c,f d) 
          csds' = map fcfd csds 

、あなたはあなたのファイルの先頭に{-# LANGUAGE NoMonomorphismRestriction #-}を置くことによってそれをオフにすることができます。

GHCのマニュアルでも、それはdreaded monomorphism restrictionと呼ばれていますが、特に共有に関しては(詳細はリンク先のwikiページを参照してください)、いくつかのトリッキーなコーナーケースがあります。回避する。この場合、タイプシグネチャを追加することをお勧めします。

+3

monomorphismの制限は、無意味な形式で書かれた関数(関数ではない値だけでなく)にも影響するので、明示的なパラメータを使って 'f'を定義すると、型署名を与えないでください。 – sepp2k

+0

型署名 'f :: Transformable a => a - > a'は、型署名に指定された関数を保持します。それがなければ、コンパイラは 'f'が' Matrix - > Matrix'型であることをその最初の用法として推論します。これを明確にしていただきありがとうございます。特に私は署名がこの単形体の制限を解決できるかどうか分からなかった。 – epsilonhalbe

関連する問題