Saya mencari jenis algoritma inferensi untuk bahasa yang saya kembangkan, tetapi saya tidak dapat menemukan yang sesuai dengan kebutuhan saya karena biasanya adalah:
- à la Haskell, dengan polimorfisme tetapi tanpa kelebihan ad-hoc
- à la C ++ (otomatis) di mana Anda memiliki kelebihan ad-hoc tetapi fungsinya monomorfik
Khususnya sistem tipe saya (menyederhanakan) (Saya menggunakan sintaksis Haskellish tapi ini adalah agnostik bahasa):
data Type = Int | Double | Matrix Type | Function Type Type
Dan saya punya operator * yang kelebihan beban:
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
Dll ...
Dan saya ingin menyimpulkan jenis yang mungkin untuk
(2*(x => 2*x))*6
(2*(x => 2*x))*{{1,2},{3,4}}
Yang pertama adalah Int
, yang kedua Matrix Int
.
Contoh (itu tidak berfungsi):
{-# 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
type-theory
type-inference
miniBill
sumber
sumber
Jawaban:
Saya sarankan melihat disertasi Geoffrey Seward Smith
Seperti yang mungkin sudah Anda ketahui, cara kerja algoritma inferensi tipe umum adalah bahwa mereka melintasi pohon sintaks dan untuk setiap subekspresi, mereka menghasilkan batasan tipe. Kemudian, mereka mengambil kendala ini, mengasumsikan hubungan di antara mereka, dan menyelesaikannya (biasanya mencari solusi yang paling umum).
Ketika Anda juga memiliki kelebihan beban, ketika menganalisis operator kelebihan beban Anda menghasilkan beberapa jenis kendala, bukan satu, dan menganggap disjungsi di antara mereka, jika kelebihan beban dibatasi. Karena pada dasarnya Anda mengatakan bahwa operator dapat memiliki `` baik ini, atau ini, atau tipe itu. "Jika tidak terikat, seseorang perlu menggunakan kuantifikasi universal, seperti halnya dengan tipe polimorfik, tetapi dengan kendala tambahan yang membatasi aktual tipe overloading. Paper I referensi membahas topik-topik ini secara lebih mendalam.
sumber
Anehnya, Haskell sendiri adalah
sempurnahampir mampu contoh; Hindley-Milner benar-benar baik-baik saja dengan kelebihan beban, asalkan itu terbatas:Kamu sudah selesai! Yah, kecuali bahwa Anda perlu default. Jika bahasa Anda memungkinkan default
Times
kelas untukInt
(dan kemudianDouble
), maka contoh Anda akan bekerja persis seperti yang dinyatakan. Cara lain untuk memperbaikinya, tentu saja, adalah untuk tidak secara otomatis mempromosikanInt
untukDouble
, atau hanya melakukannya ketika segera diperlukan, dan untuk penggunaanInt
literal sebagaiInt
hanya (sekali lagi, mempromosikan hanya bila segera diperlukan); solusi ini juga akan berfungsi.sumber