Проблема в том, что show :: (t -> t -> t) -> String
должно работать для любой функции, работающей с любым типом t
. Вы предполагаете, что t
является логическим значением, которое недопустимо, потому что (согласно GHC) «t
является переменной жесткого типа» и не может быть объединено со специализированным типом.
Одним из возможных решений будет специализация вашего экземпляра на Bool
(необходимо FlexibleInstances
)
{-#LANGUAGE FlexibleInstances #-}
instance Show (Bool -> Bool -> Bool) where
show b = show $ b True False
Но это уменьшит общность логики вашей Церкви.
Невозможно определить гибкое решение, которое будет работать с любым типом, потому что вам понадобится два представителя этого типа, которые описали бы случаи true и false , и там такие типы, как Void
, которые не имеют (определенных) значений.
Идея, которая приходит мне в голову и является достаточно универсальной, состоит в том, чтобы добавить еще несколько классовых ограничений к t
:
{-#LANGUAGE FlexibleInstances #-}
import Data.Boolean
instance (Show t, Boolean t) => Show (t -> t -> t) where
show b = show $ b true false
Класс Boolean
собирает типы, которые в некоторых терминах могут пониматься как логические значения. Например для Bool
:
instance Boolean Bool where
true = True
false = False
notB = not
(||*) = (||)
(&&*) = (&&)
И теперь мы можем гарантировать, что
t
это то, что вы можете на самом деле show
- Существует как минимум два допустимых и разных значения типа
t
, которые отображаются как true
и false
Каковы обязательные обстоятельства, чтобы реально иметь возможность show
функционировать такой подписью таким образом.
ВАЖНО
Следующий пример не будет работать:
show (true :: (Show t, Boolean t) => t -> t -> t)
Проблема в том, что проверщик типов не будет угадывать, какой t
у вас будет здесь. Это решение предоставляет действительный и рабочий экземпляр, но только для полностью созданных экземпляров типов. Если вы получите ошибку неоднозначности, вам нужно будет указать, что такое t
:
show (true :: Bool -> Bool -> Bool)
>>> "True"
show (true :: Int -> Int -> Int) -- assuming Boolean instance
>>> "1"
EDIT
Еще одна идея была упомянута в комментариях. Решение будет заключаться в том, чтобы обернуть вашу Церковь логическим Rank2Type
:
{-# LANGUAGE Rank2Types #-}
newtype ChBool = ChBool (forall t. t -> t -> t)
Что позволит t
быть любым типом, независимым от контекста. Тогда вы можете определить случайный экземпляр следующим образом:
instance Show ChBool where
show (ChBool f) = show $ f True False