问题
Using ViewPatterns
and Data.Typeable
, I’ve managed to write a function that allows me to write something resembling case analysis on types. Observe:
{-# LANGUAGE GADTs, PatternSynonyms, RankNTypes, ScopedTypeVariables
, TypeApplications, TypeOperators, ViewPatterns #-}
import Data.Typeable
viewEqT :: forall b a. (Typeable a, Typeable b) => a -> Maybe ((a :~: b), b)
viewEqT x = case eqT @a @b of
Just Refl -> Just (Refl, x)
Nothing -> Nothing
evilId :: Typeable a => a -> a
evilId (viewEqT @Int -> Just (Refl, n)) = n + 1
evilId (viewEqT @String -> Just (Refl, str)) = reverse str
evilId x = x
The above evilId
function is very evil, indeed, since it uses Typeable
to completely subvert parametricity:
ghci> evilId True
True
ghci> evilId "hello"
"olleh"
Since I love being evil, I am very pleased with this, but the above syntax is very noisy. I would love to be able to write the same code more clearly, so I decided to write a pattern synonym:
pattern EqT :: forall b a. (Typeable a, Typeable b) => (a ~ b) => b -> a
pattern EqT x <- (viewEqT @b -> Just (Refl, x))
I figured that I would be able to use this pattern synonym to make my evil case analysis much easier to read:
evilId :: Typeable a => a -> a
evilId (EqT (n :: Int)) = n + 1
evilId (EqT (str :: String)) = reverse str
evilId x = x
Sadly, this does not work at all. GHC does not seem to consult my type annotations before typechecking the pattern, so it believes b
is an ambiguous variable in each pattern. Is there any way I can cleanly wrap these patterns with a pattern synonym, or will I be stuck with my longer view patterns?
回答1:
If the goal is to find some clean syntax to implement your evilId
function, you can write it like this:
{-# Language ScopedTypeVariables, GADTs, TypeApplications #-}
module Demo where
import Data.Typeable
evilId :: forall a. Typeable a => a -> a
evilId x
| Just Refl <- eqT @a @Int = x+1
| Just Refl <- eqT @a @String = reverse x
| otherwise = x
This doesn't help with the ambiguities surrounding your pattern synonyms, unfortunately.
来源:https://stackoverflow.com/questions/41753345/how-can-i-write-this-pattern-synonym-without-ambiguous-type-errors