Я, кажется, сталкивался с подобным. Я так понимаю, он выводит тип, анализируя не вообще всё, а как только сможет сделать вывод о типе. Иногда он из-за этого ставит конкретный тип вместо класса. Из первого выражения для deduceTypes он делает правильный вывод о типе deduceTypes, а из второго - о конкретном типе входящей туда переменной op (из BoolOp следует, что это CmpPredicate), и как следствие - о типе deduceOperationTypes, более узком, чем следует из ее определения. Ну и, анализируя третье, выдает конфликт типов, поскольку тип для deduceOperationTypes он уже вывел. А расширять уже выведенный тип посредством поиска, что общего между CmpPredicate и BinaryOperation, хаскель не обучен.
Так, по логике, если он будет пытаться следить за самым широким вариантом, то он может правильно вывести тип первого аргумента для deduceOperationTypes (он следует из применения resultType), но не сможет грамотно ограничить второй и третий. Или сможет, но за невменяемое время.
Это polymorphic recursion косячит. Вывод типов таких функций завершается при первом удобном случае (потому что иначе вывод может не завершиться), а дальше уже в игру вступает type checker.
Простой пример:
> let { f Nothing = f (Just "String"); f (Just x) = f (Just True) }
ломается, хотя
> let { f :: Maybe t -> Bool; f Nothing = f (Just "String"); f (Just x) = f (Just True) }
Comments 5
Reply
Так, по логике, если он будет пытаться следить за самым широким вариантом, то он может правильно вывести тип первого аргумента для deduceOperationTypes (он следует из применения resultType), но не сможет грамотно ограничить второй и третий. Или сможет, но за невменяемое время.
Reply
Reply
Простой пример:
> let { f Nothing = f (Just "String"); f (Just x) = f (Just True) }
ломается, хотя
> let { f :: Maybe t -> Bool; f Nothing = f (Just "String"); f (Just x) = f (Just True) }
работает
Reply
Reply
Leave a comment