型推論+オーバーロード


9

開発中の言語の型推論アルゴリズムを探していますが、通常は次のいずれかであるため、自分のニーズに合った型推論アルゴリズムを見つけることができませんでした。

  • アラモスHaskell、多態性はあるがアドホックなオーバーロードはない
  • アラカルトC ++(自動)で、アドホックなオーバーロードはあるが、関数は単相

特に、私のタイプシステムは(簡素化)です(Haskellish構文を使用していますが、これは言語に依存しません)。

data Type = Int | Double | Matrix Type | Function Type Type

そして、私はかなりのオーバーロードを持っている演算子*を持っています:

Int -> Int -> Int
(Function Int Int) -> Int -> Int
Int -> (Function Int Int) -> (Function Int Int)
(Function Int Int) -> (Function Int Int) -> (Function Int Int)
Int -> Matrix Int -> Matrix Int
Matrix Int -> Matrix Int -> Matrix Int
(Function (Matrix Int) (Matrix Int)) -> Matrix Int -> Matrix Int

等...

そして、私は可能なタイプを推測したい

(2*(x => 2*x))*6
(2*(x => 2*x))*{{1,2},{3,4}}

1つ目はInt、2つ目Matrix Intです。

例(機能しない):

{-# LANGUAGE OverlappingInstances, MultiParamTypeClasses,
  FunctionalDependencies, FlexibleContexts,
  FlexibleInstances, UndecidableInstances #-}

import qualified Prelude
import Prelude hiding ((+), (*))
import qualified Prelude

newtype WInt = WInt { unwrap :: Int }

liftW f a b = WInt $ f (unwrap a) (unwrap b)

class Times a b c | a b -> c where
(*) :: a -> b -> c

instance Times WInt WInt WInt where
(*) = liftW (Prelude.*)

instance (Times a b c) => Times a (r -> b) (r -> c) where
x * g = \v -> x * g v

instance Times (a -> b) a b where
f * y = f y

two = WInt 2
six = WInt 6

test :: WInt
test = (two*(\x -> two*x))*six

main = undefined

3
これはCS理論スタック交換の基準を満たしていないようですが、より数学的または理論的な答えを探しているようです。コンピュータサイエンスはこれに適していると思います。より良い答えを得るためにあなたに動きを要求したので、それが評判が良いと思われる場所に送ります。
Thomas Owens、

回答:


9

ジェフリー・スワード・スミスの論文を見ることをお勧めします

おそらくすでにご存じのとおり、一般的な型推論アルゴリズムが機能する方法は、構文ツリーを走査し、すべての部分式に対して型制約を生成することです。次に、この制約を取り、それらの間の結合を仮定し、それらを解決します(通常、最も一般的なソリューションを探します)。

オーバーロードもある場合、オーバーロードされた演算子を分析するとき、1つではなく複数の型制約を生成し、オーバーロードが制限されている場合は、それらの論理和を仮定します。演算子は「これ、またはこれ、またはその型のいずれか」を持つことができると本質的に言っているので、無制限の場合は、多相型と同様に、普遍的な数量化に頼る必要がありますが、実際の制約に追加の制約がありますタイプのオーバーロード。私が参照する論文では、これらのトピックをより深くカバーしています。


どうもありがとう、これが私が探していた答えです
miniBill

7

奇妙なことに、ハスケル自体は完璧に 近いあなたの例が可能。Hindley-Milnerは、それが十分に制限されている限り、オーバーロードしてもまったく問題ありません。

{-# LANGUAGE OverlappingInstances, MultiParamTypeClasses,
             FunctionalDependencies, FlexibleContexts,
             FlexibleInstances #-}
import Prelude hiding ((*))

class Times a b c | a b -> c where
    (*) :: a -> b -> c

instance Times Int Int Int where
    (*) = (Prelude.*)

instance Times Double Double Double where
    (*) = (Prelude.*)

instance (Times a b c) => Times (r -> a) (r -> b) (r -> c) where
    f * g = \v -> f v * g v

instance (Times a b c) => Times a (r -> b) (r -> c) where
    x * g = \v -> x * g v

instance (Times a b c) => Times (r -> a) b (r -> c) where
    f * y = \v -> f v * y

type Matrix a = (Int, Int) -> a

完了です!まあ、デフォルトが必要なことを除いて。言語がTimesクラスをデフォルトにInt(そしてDouble)にデフォルト設定できる場合、例は記載どおりに機能します。もちろん、それを修正するもう1つの方法は、に自動的に昇格IntDoubleないか、すぐに必要な場合にのみそれを実行し、IntリテラルIntのみを使用することです(ここでも、すぐに必要な場合にのみ昇格します)。このソリューションも機能します。


2
どうもありがとうございました!(ただし、拡張機能の数は9kを超えています)
miniBill

1
機能しないideone.com/s9rSi7
miniBill

1
デフォルトの問題ではありません:ideone.com/LrfEjX
miniBill

1
ああ、すみません、その時あなたを誤解しました。さて、私は...(私が思う)不履行たくない
miniBill

2
コンパイルする例を作ってみませんか?
miniBill 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.