Ketik inferensi + kelebihan muatan

9

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
miniBill
sumber
3
Tampaknya ini tidak memenuhi kriteria untuk CS Theory Stack Exchange, tetapi sepertinya Anda sedang mencari jawaban yang lebih matematis atau teoretis. Saya pikir Ilmu Komputer mungkin cocok untuk ini. Karena Anda meminta langkah untuk mendapatkan jawaban yang lebih baik, saya akan mengirimkannya ke tempat yang kemungkinan akan diterima dengan baik.
Thomas Owens

Jawaban:

9

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.

bellpeace
sumber
Terima kasih banyak, ini adalah jawaban yang saya cari
miniBill
7

Anehnya, Haskell sendiri adalah sempurna hampir mampu contoh; Hindley-Milner benar-benar baik-baik saja dengan kelebihan beban, asalkan itu terbatas:

{-# 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

Kamu sudah selesai! Yah, kecuali bahwa Anda perlu default. Jika bahasa Anda memungkinkan default Timeskelas untuk Int(dan kemudian Double), maka contoh Anda akan bekerja persis seperti yang dinyatakan. Cara lain untuk memperbaikinya, tentu saja, adalah untuk tidak secara otomatis mempromosikan Intuntuk Double, atau hanya melakukannya ketika segera diperlukan, dan untuk penggunaan Intliteral sebagai Inthanya (sekali lagi, mempromosikan hanya bila segera diperlukan); solusi ini juga akan berfungsi.

Api Ptharien
sumber
2
Terima kasih banyak! (meskipun jumlah ekstensi lebih dari 9k)
miniBill
1
Tidak bekerja ideone.com/s9rSi7
miniBill
1
itu bukan masalah default: ideone.com/LrfEjX
miniBill
1
Oh, maaf, saya salah paham dengan Anda. Yah, saya tidak ingin default (saya pikir) ..
miniBill
2
Bisakah Anda mencoba menghasilkan contoh yang mengkompilasi?
miniBill