2016-04-02 1 views
3

TL; DR

Есть ли способ имитировать пустые ограничения с помощью GHC < 7.8.1? Что-то похож наЕсть ли способ синтаксически имитировать пустые ограничения с помощью GHC <7.8.1?

{-# LANGUAGE NullaryTypeClasses #-} 
class HasCallStack 
instance HasCallStack 

так что, например,

foo :: HasCallStack => Int -> Int 

технически такой же, как

foo :: Int -> Int 

Мотивация

GHC 8.0.1 вводит HasCallStack как:

HasCallStack = (?callStack :: CallStack) 

Для прокладки совместимости Я хочу, чтобы определить HasCallStack для всех версии GHC назад к 7.0.1.

Для версий GHC, поддерживающих неактивные стеки вызовов на основе параметров, HasCallStack должен быть функционально эквивалентен тому, что мы имеем в GHC 8.0.1.

Для версий GHC, что отсутствие поддержки неявного вызова на основе параметров стека (то есть все версии GHC < 7.10.2), HasCallStack должны быть функционально эквивалентны пустому ограничения.

Для полноты, вот код, который мы могли бы использовать, если только заботиться о GHC 7.8.1 и позже:

#if MIN_VERSION_base(4,8,1) 
type HasCallStack = (?callStack :: CallStack) 
#else 
class HasCallStack 
instance HasCallStack 
#endif 

Есть ли способ, чтобы сделать эту работу для более старых версий GHC?

Для справки я добавлю свое текущее решение в качестве ответа. Но я бы хотел получить вход на других способах решения этой проблемы.

+0

У меня нет версии ghc старше 7.10 - это 'type HasCallStack = (() :: Constraint)' work? Вам нужны '-XConstraintKinds' и' импорт GHC.Exts (Constraint) ' – user2407038

+0

' type HasCallStack = (() :: Constraint) 'работает для версий GHC в GHC 7.4.1. Это мило! –

+0

Вы также можете использовать '#define HasCallStack()' - это позволит избежать 'ConstraintKinds' и будет поддерживать больше версий ghc. '()' является допустимым ограничением даже в Haskell 98. – user2407038

ответ

4

Я не знаю, как поддерживать тот же синтаксис, который у нас есть в GHC 8.0.1. Тем не менее, можно дополнительно добавить ограничение, используя синоним типа и Rank2Types. Следующий код работает для всех версий GHC до 7.0.1.

#if MIN_VERSION_base(4,8,1) 
type HasCallStack a = (?callStack :: CallStack) => a 
#else 
type HasCallStack a = a 
#endif 

Пример из вашего вопроса

foo :: HasCallStack => Int -> Int 

становится

foo :: HasCallStack(Int -> Int) 

Обратите внимание, что это довольно прочный. Я не сталкивался с ситуацией, когда это не сработало, например. даже работает, когда foo имеет другие ограничения или когда foo - это метод class.

+0

'RankNTypes' требуется только для (эффективно) использования' HasCallStack' в левой части стрелки, правильно? – dfeuer

+0

Из того, что я пробовал, вам нужно «Rank2Types' /' RankNTypes' для определения «HasCallStack». В модулях, которые просто используют 'HasCallStack', вам нужны только' FlexibleContexts'. –