Как написать экземпляр для всех типов в классе другого типа? - PullRequest
9 голосов
/ 16 января 2012

Мне нужно определить класс типов Truthy, который содержит метод true, преобразующий экземпляр класса типов в значение Bool.

Мое объявление класса типов:

class Truthy a where
    true :: a -> Bool

Далее я должен определить экземпляры этого класса для различных типов, включая списочные и числовые типы.Я сделал это для списков и Int s, но есть ли способ сделать это для всех числовых типов одновременно?

На основании моего объявления Int:

instance Truthy Int where
    true = (/=) 0

У меня естьпопытался добавить ограничение класса типа, но оно не работает:

instance (Num a) => (Truthy a) where
    true = (/=) 0::a

Если есть способ сделать это похожим на то, что я имел в виду, или я должен просто определить его для каждого числового типа отдельно?

1 Ответ

10 голосов
/ 16 января 2012

Это может не помочь для домашней работы, но вы на самом деле можете написать такую ​​декларацию. Вы просто должны включить -XFlexibleInstances, чтобы сделать это. По крайней мере, в GHC вы можете сделать это, поместив прагму вверху вашего файла:

{-# LANGUAGE FlexibleInstances #-}

Если вы внимательно посмотрите на полученное сообщение об ошибке, оно говорит что-то вроде «Используйте -XF FlexibleInstances, если вы хотите отключить это».

В этом конкретном случае вам также необходимо включить UndecidableInstances и OverlappingInstances:

 {-# LANGUAGE FlexibleInstances,  UndecidableInstances, OverlappingInstances #-}

Вам нужен FlexibleInstances, потому что стандартный Haskell не допускает экземпляры в любой форме, где переменная типа появляется более одного раза в голове. Это совершенно нормально - это одно из самых распространенных расширений (согласно этот вопрос ).

Вам нужен UndecidableInstances, потому что объявление вашего экземпляра потенциально может привести к тому, что средство проверки типов будет работать постоянно. Я думаю, что использование UndecidableInstances предотвращает это, ограничивая, насколько глубоко он будет проверять при попытке уменьшить экземпляр. Это обычно - в том числе и в этом случае - хорошо, но теоретически может определить, проходит ли конкретная программа проверки типа в зависимости от реализации . Тем не менее, это должно работать в вашем случае.

Как отметил Хаммар, вам нужно включить OverlappingInstances, потому что "контекст" экземпляра игнорируется при проверке, перекрываются ли они. В этом случае контекстом является бит Num a. Таким образом, экземпляры - для проверки, перекрываются ли они - читаются как instance Truthy a... и перекрываются со всем. С включенным OverlappingInstances вам просто нужно иметь один экземпляр, который наиболее специфичен для этой работы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...