Все параметры типа, зависящие друг от друга в функциональных зависимостях

Скажем, у меня есть класс типа с параметрами типа n, и я хочу, чтобы любой из них однозначно определял все остальные. Достаточно ли этого, чтобы зависимости составляли цикл, как в

class Foo a b c | a -> b, b -> c, c -> a

(линейный), где есть путь от каждого параметра к каждому другому, или мне нужно развернуть все возможные пути, как в

class Bar a b c | a -> b, a -> c, b -> a, b -> c, c -> a, c -> b

(квадратичный)? Есть ли наблюдаемая разница между этими двумя? И как насчет

class Baz a b c | a -> b c, b -> a c, c -> a b

Ответы

Ответ 1

Оперативно все вышеперечисленное эквивалентно:

Прежде всего, a -> b c в буквальном смысле то же самое, что и a -> b, a -> c.

Затем предположим, что мы получили Foo a b c => (a, b, c). Скажем, мы понимаем, что a ~ A. Мы находим a -> b fundep и просматриваем экземпляры, чтобы найти b ~ B. Снова мы находим b -> c fundep и реализуем c ~ C. Вуале мы получили (A, B, C).

Если бы мы имели Bar a b c => (a, b, c) с a ~ A, мы бы нашли a -> b и b ~ B, однако перед тем, как найти b -> c, мы бы нашли a -> c.

Единственное различие заключается в том, какие стрелки fundep используются для вывода типов. a -> b, b -> c и a -> b, a -> c не могут давать разные результаты.