Digitare inferenza + sovraccarico


9

Sto cercando un algoritmo di inferenza del tipo per un linguaggio che sto sviluppando, ma non sono riuscito a trovarne uno adatto alle mie esigenze perché di solito sono:

  • alla Haskell, con polimorfismo ma nessun sovraccarico ad hoc
  • à C ++ (auto) in cui si ha un sovraccarico ad hoc ma le funzioni sono monomorfe

In particolare il mio sistema di tipi è (semplificando) (sto usando la sintassi di Haskellish ma questo è agnostico):

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

E ho un operatore * che ha alcuni sovraccarichi:

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

Eccetera...

E voglio dedurre possibili tipi per

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

Il primo è Int, il secondo Matrix Int.

Esempio (che non funziona):

{-# 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
Questo non sembra soddisfare i criteri per CS Theory Stack Exchange, ma sembra che tu stia cercando una risposta più matematica o teorica. Penso che l'Informatica possa essere appropriata per questo. Dal momento che hai richiesto una mossa per ottenere risposte migliori, la invierò dove probabilmente sarà ben accolta.
Thomas Owens,

Risposte:


9

Suggerirei di guardare la tesi di Geoffrey Seward Smith

Come probabilmente già saprai, il modo in cui funzionano gli algoritmi di inferenza di tipo comune è che attraversano l'albero di sintassi e per ogni sottoespressione generano un vincolo di tipo. Quindi, prendono questi vincoli, assumono congiunzione tra loro e li risolvono (in genere alla ricerca di una soluzione più generale).

Quando si ha anche un sovraccarico, quando si analizza un operatore sovraccarico si generano diversi vincoli di tipo, anziché uno, e si presuppone la disgiunzione tra di essi, se il sovraccarico è limitato. Perché stai essenzialmente dicendo che l'operatore può avere `` o questo, o questo o quel tipo. "Se non ha limiti, è necessario ricorrere alla quantificazione universale, proprio come con i tipi polimorfici, ma con vincoli aggiuntivi che vincolano il reale tipi di sovraccarico Il documento a cui faccio riferimento tratta questi argomenti in modo più approfondito.


Grazie mille, questa è la risposta che stavo cercando
miniBill

7

Stranamente, Haskell stesso è perfettamente quasi in grado di vostro esempio; Hindley-Milner sta benissimo con il sovraccarico, purché sia ​​ben limitato:

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

Hai finito! Bene, tranne che hai bisogno di default. Se la tua lingua consente di impostare la Timesclasse come predefinita Int(e quindi Double), i tuoi esempi funzioneranno esattamente come indicato. L'altro modo per risolvere il problema, naturalmente, è quello di non promuovere l'automaticamente Inta Double, o solo a farlo quando immediatamente necessarie, e di utilizzare Intletterali come Intsolo (ancora una volta, la promozione solo quando immediatamente necessario); questa soluzione funzionerà anche.


2
Grazie mille! (sebbene il numero di estensioni sia superiore a 9k)
miniBill

1
Non funziona ideone.com/s9rSi7
miniBill

1
non è un problema di default: ideone.com/LrfEjX
miniBill

1
Oh, scusa, allora ti ho frainteso. Bene, non voglio essere inadempiente (credo) ..
miniBill

2
Potresti provare a produrre un esempio che compila?
miniBill
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.