Введіть умовивід + перевантаження


9

Я шукаю алгоритм виводу типу для мови, яку я розробляю, але не зміг знайти той, який відповідає моїм потребам, оскільки вони зазвичай є:

  • à la Haskell, з поліморфізмом, але без особливих перевантажень
  • à la 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}}

Перше - Intдруге 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, але схоже, що ви шукаєте більш математичну чи теоретичну відповідь. Я думаю, що комп’ютерна наука може бути доречною для цього. Оскільки ви подали запит на перехід, щоб отримати кращі відповіді, я надішлю його туди, де він, ймовірно, буде добре сприйнятий.
Томас Оуенс

Відповіді:


9

Я б запропонував переглянути дисертацію Джеффрі Сьюарда Сміта

Як ви, напевно, вже знаєте, спосіб роботи загальних алгоритмів виводу типу полягає в тому, що вони обходять дерево синтаксису і для кожної піддепресії вони створюють обмеження типу. Потім вони беруть ці обмеження, припускають сполучення між ними і вирішують їх (зазвичай шукають найбільш загальне рішення).

Якщо у вас також є перевантаження, під час аналізу перевантаженого оператора ви генеруєте кілька обмежень типу, замість одного, і припускаєте диз'юнкцію між ними, якщо перевантаження обмежена. Тому що ви по суті говорите, що оператор може мати `` або це, або це, або той тип. "Якщо це без обмежень, потрібно вдатися до універсальної кількісної оцінки, як і при поліморфних типах, але з додатковими обмеженнями, які обмежують фактичне Перевантажувальні типи Доповідь, на яку я посилаюсь, висвітлює ці теми більш глибоко.


Дякую дуже, це відповідь, яку я шукав
miniBill

7

Як не дивно, сам Haskell є абсолютно майже здатний ваш приклад; Хіндлі-Мілнер цілком гарно перевантажується, якщо вона добре обмежена:

{-# 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), ваші приклади працюватимуть точно так, як зазначено. Інший спосіб виправити це, звичайно, не автоматично просувати Intдо Double, або тільки робити це , коли відразу ж необхідно, і використання Intлітералів , як Intтільки (знову ж , просуваючи тільки тоді , коли відразу необхідно); це рішення також спрацює.


2
Дуже дякую! (хоча кількість розширень перевищує 9 к)
miniBill

1
Не працює ideone.com/s9rSi7
miniBill

1
це не проблема дефолту: ideone.com/LrfEjX
miniBill

1
О, вибачте, я тоді вас зрозумів неправильно. Ну, я не хочу дефолту (я думаю) ..
miniBill

2
Чи можете ви спробувати створити приклад, який компілюється?
міні-банк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.