У меня есть ситуация, когда я сейчас использую крайне страшную функцию unsafeCoerce. Это не для чего-то важного, к счастью, но мне было интересно, является ли это безопасным использованием этой функции или будет ли другой способ решить эту конкретную проблему, о которой знают другие люди.
Код, который у меня есть, выглядит примерно так:
data Token b = Token !Integer
identical :: Token a -> Token b -> Bool
identical (Token a) (Token b) = a == b
data F a = forall b. F (Token b) (a -> b)
retrieve :: Token b -> F a -> Maybe (a -> b)
retrieve t (F t' f) = if identical t t' then Just (unsafeCoerce f) else Nothing
Две дополнительные вещи, которые следует отметить, заключаются в том, что эти токены используются в монаде, который я использую, чтобы гарантировать, что предложение целых чисел для них уникально (т.е. я не делаю то же самое в два раза). Я также использую переменную forall quantified shadow type так же, как и ST monad, чтобы убедиться, что (при условии, что используются только те методы, которые я раскрываю в модуле), нет способа вернуть токен (или, по сути, даже F) из монады, не являясь ошибкой типа. Я также не выставляю конструктор токенов.
Я думаю, что, насколько я вижу, это должно быть безопасное использование unsafeCoerce, как я могу сказать (надеюсь) довольно высокую уверенность в том, что ценность, которую я принуждаю, на самом деле является именно тем типом, которым я являюсь принуждая его, но я могу ошибаться. Я также попытался использовать Data.Typeable, который работает хорошо, но на данный момент я пытаюсь это избежать ограничения Typeable, тем более, что gcast, похоже, делает что-то во многом похожее, и мне все равно нужны токены, чтобы различать разные Fs того же типа.
Большое спасибо за любую помощь/совет.