コンパイルすると、次のエラーメッセージが表示されます。
重複する型の署名:
weightedMedian.hs:71:0-39:findVal :: [ValPair]->ダブル->ダブル
weightedMedian.hs:68:0-36:findVal :: [ValPair]-> Int-> Double
私の解決策は、findValIとfindValDを用意することです。ただし、findValIはInt型をDoubleに変換し、findValDを呼び出すだけです。
また、Num(Int、Double)の型でパターンマッチングを行うことができないため、型のシグネチャを
findVal :: [ValPair] -> Num -> Double
多くの言語では、別の名前は必要ありません。 Haskellで異なる名前が必要なのはなぜですか?これを言語に追加するのは難しいでしょうか?それともドラゴンはいますか?
アドホック多相性(および名前のオーバーロード)は、タイプクラスによってHaskellで提供されます。
class CanFindVal a where
findVal :: [ValPair] -> a -> Double
instance CanFindVal Double where
findVal xs d = ...
instance CanFindVal Int where
findVal xs d = findVal xs (fromIntegral d :: Double)
この場合、findVal
"really"にはDouble
が必要なので、常にdoubleをとる必要があり、intを渡す必要がある場合は、呼び出しサイトでfromIntegral
を使用するだけです。一般に、無差別ではなく、実際に異なる動作やロジックが関係している場合に型クラスが必要になります。
両方をサポートするfindVal :: [ValPair] -> Double -> Double
およびfindVal :: [ValPair] -> Int -> Double
アドホック多相性( http://www.haskell.org/haskellwiki/Ad-hoc_polymorphism を参照)が必要ですが、これは一般的に危険です。その理由は、アドホック多相性により、同じ構文でセマンティクスを変更できるためです。
Haskellはいわゆるパラメトリック多型を好みます。これは、型変数がある型シグネチャで常に見られます。
Haskellは、型クラスを介してアドホック多相性のより安全なバージョンをサポートしています。
3つのオプションがあります。
このような:
findVal :: Num a => [ValPair] -> a -> Double
{-# SPECIALISE findVal :: [ValPair] -> Int -> Double #-}
{-# SPECIALISE findVal :: [ValPair] -> Double -> Double #-}
findVal = ...
HaskellはC++スタイルのオーバーロードをサポートしていません(型クラスでもある程度サポートしていますが、同じようには使用していません)。そして、ええ、それを追加することに関連するいくつかのドラゴンがあり、主に型推論に関係しています(指数関数的な時間になるか、決定不能になるか、そのようなものになります)。ただし、このような「便利な」コードがHaskellで表示されることはほとんどありません。 Int
とDouble
のどちらですか? Int
メソッドはDouble
メソッドに委任するので、私の推測では、Double
が「正しい」メソッドであると思います。それを使うだけです。文字通りのオーバーロードのため、次のように呼び出すことができます。
findVal whatever 42
そしてその 42
はDouble
として扱われます。これが機能しない唯一のケースは、基本的にInt
である何かを取得し、それをこの引数として渡す必要がある場合です。次に、fromIntegral
を使用します。しかし、コードでどこでも「正しい」タイプを使用するように努める場合、このケースはまれになります(変換する必要がある場合は、それに注意を払う価値があります)。
この場合、2番目の引数のIntとDoubleの両方を処理する関数を作成するのは簡単だと思います。 findVal
と書くだけで、2番目の引数でrealToFrac
が呼び出されます。これにより、Int
がDouble
に変換され、Double
はそのままになります。次に、怠惰な場合は、コンパイラに型を推測させます。
他の多くのプログラミング言語では、同じ名前であるが、異なるパラメータータイプなど、シグネチャ内の他のものが異なる(一種の)関数を宣言できます。これはオーバーロードと呼ばれ、アドホック多相性を実現するための最も一般的な方法です。
Haskellは、設計者がアドホック多相を実現するための最良の方法とは考えていないため、意図的にオーバーロードをサポートしていません。 Haskellの方法はむしろ制約されたポリモーフィズムであり、型クラスとクラスインスタンスの宣言が含まれます