Jak działa inferencja typu w obecności zależności funkcjonalnych

Rozważ poniższy kod:

{-# LANGUAGE MultiParamTypeClasses,FlexibleInstances,FunctionalDependencies,UndecidableInstances,FlexibleContexts  #-}
class Foo a c | a -> c
instance Foo Int Float 
f :: (Foo Int a) => Int -> a 
f = undefined

Teraz, gdy widzę wywnioskowany typ f w ghci

> :t f
> f :: Int -> Float

Teraz, jeśli dodam następujący kod

g :: Int -> Float 
g = undefined 

h :: (Foo Int a) => Int -> a 
h = g

Dostaję błąd

Could not deduce (a ~ Float)

Nie jestem w stanie zrozumieć, co tu się stało? OgraniczenieFoo Int a powinien był ograniczyć typh doInt -> Float jak pokazano w wywnioskowanym typief.

Czy to dlatego, że występuje unifikacja typów przed rozwiązaniem instancji?

[Aktualizacja]

Wyjaśnienie podane przez Dana Doela na liście dyskusyjnej kawiarni

Odpowiedź, jak sądzę, jest taka, że ​​różnica między implementacją fundeple a rodzinami typu jest informacją o ograniczeniach lokalnych. Fundipy nie propagują lokalnego.

Tak więc w pierwszej definicji masz lokalnie dostarczoneInt -> a„, który jest akceptowalny przez GHC. Następnie odkrywa zewnętrznie funkcję, którą „(Foo Int a) => Int -> a' jest aktualneInt -> Float.

W drugiej definicji próbujesz daćInt -> Float„, ale GHC wie tylko lokalnie, że musisz dostarczyć”Int -> a„z ograniczeniem”Foo Int a„które toprzyzwyczajenie użyj, aby to ustalića ~ Float.

Nie jest to związane z funduszami. Można stworzyć wersję funduszy, która ma lokalne reguły ograniczające (łatwo, tłumacząc na nowe typy rodzin). Ale różnica polega również na tym, że nakładające się instancje są obsługiwane dla funduszy, a nie dla rodzin typu. Ale teraz nie wejdę w to.

Nadal nie rozumiem, co to znaczy. Więc wciąż szukam lepszej zrozumiałej odpowiedzi.

questionAnswers(1)

yourAnswerToTheQuestion