2017-02-20 14 views
4

К тому времени, когда я впервые прочитал серьезный criticism on -XUndecidableInstances, я уже полностью привык к этому, рассматривая его как просто удаление раздражающего ограничения. Haskell98 должен сделать компиляторы проще для реализации.Как можно разблокировать экземпляры на самом деле повесить компилятор?

Фактически, я столкнулся с множеством приложений, где нужны нерешимые экземпляры, но не там, где они фактически вызвали проблемы, связанные с неразрешимостью. Пример Луки является проблематичным для совершенно иной причине

class Group g where 
    (%) :: g -> g -> g 
    ... 
instance Num g => Group g where 
    ... 

- ну, это, безусловно, будет перекрывается любым надлежащим Group, например, так неразрешимость является наименее нашего беспокойства: это на самом деле ООН детерминированным!

Но, честно говоря, я с тех пор держал «неразрешимые экземпляры, возможно, повесить компилятор» в затылок.

Откуда он был приобретен, когда я прочитал this challenge on CodeGolf.SE, запросив код, который будет бесконечно зависать компилятором. Ну, звучит как работа для неразрешимых экземпляров, не так ли?

Оказывается, я не могу заставить их это сделать. Следующие компилирует в кратчайшие сроки, по крайней мере, из GHC-7.10:

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-} 
class C y 
instance C y => C y 
main = return() 

Я могу даже использовать методы класса, и они будут вызывать только петлю на выполнения:

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-} 
class C y where y::y 
instance C y => C y where y=z 
z :: C y=>y; z=y 
main = print (y :: Int) 

Но во время выполнения петли ничего необычного, вы можете легко скопировать их в Haskell98.

Я также попробовал разные, менее прямые петли, такие как

{-# LANGUAGE FlexibleContexts, UndecidableInstances #-} 
data A x=A 
data B x=B 
class C y 
instance C (A x) => C (B x) 
instance C (B x) => C (A x) 

Опять же, никаких проблем во время компиляции.

Итак, что на самом деле необходимо, чтобы повесить компилятор в разрешении экземпляров класса unesableable type?

+0

Возможно, вам нужно что-то сделать, чтобы заставить компилятор решить, является ли 'Int' экземпляром' C'. – immibis

ответ

10

Я не думаю, что я когда-либо на самом деле повесил компилятор. Я могу заставить его переполнять стек, изменив ваш первый пример. Кажется, что происходит некоторое кеширование, поэтому нам нужно потребовать бесконечную последовательность уникальных ограничений, например.

data A x = A deriving (Show) 
class C y where get :: y 
instance (C (A (A a))) => C (A a) where 
    get = A 

main = print (get :: A()) 

, который дает нам

• Reduction stack overflow; size = 201 
    When simplifying the following type: 
    C (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A (A()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) 
    Use -freduction-depth=0 to disable this check 
    (any upper bound you could choose might fail unpredictably with 
    minor updates to GHC, so disabling the check is recommended if 
    you're sure that type checking should terminate) 

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

Мне очень хотелось бы услышать от кого-то, кто работает на GHC.

6

Самый простой способ получить «сокращения переполнения стека» использует семьи типа:

type family Loop where 
    Loop = Loop 

foo :: Loop 
foo = True 

Я не знаю, прямой путь, чтобы получить фактически перекручивание компиляцию на текущем GHC. Я помню, как пару раз получал петли с GHC 7.11, но я помню только один из воспроизводимых деталей:

data T where 
    T :: forall (t :: T). T 

Но это было исправлено с тех пор.

2

К моему удивлению, UndecidableInstances действительно может повесить некоторые версии GHC. Вот несколько строк кода, которые сделали это для меня:

{-# LANGUAGE FlexibleInstances  #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE TypeFamilies   #-} 
{-# LANGUAGE UndecidableInstances #-} 
module Nested where 

class Nested r ix where 

type family Lower ix :: * 

data LN 

instance Nested LN (Lower ix) => Nested LN ix where 

data L 

instance Nested LN ix => Nested L ix where 

При компиляции как часть библиотеки (непосредственно не ghc main.hs) этот код висит на неопределенный срок GHC 8.2.1

Как @luqui упоминалось, это, кажется, как ошибки, так что было сообщено как таковое: https://ghc.haskell.org/trac/ghc/ticket/14402

Edit: оказалось, что это ошибка в самом деле, что уже зафиксировано в текущей разрабатываемой версии GHC.