如何在没有模糊类型错误的情况下编写此模式同义词?

时间:2017-01-19 23:05:40

标签: haskell pattern-synonyms

使用ViewPatternsData.Typeable,我设法编写了一个函数,允许我在类型上编写类似案例分析的内容。观察:

{-# 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

上述evilId函数确实是非常邪恶的,因为它使用Typeable来完全颠覆参数:

ghci> evilId True
True
ghci> evilId "hello"
"olleh"

由于我喜欢邪恶,我对此非常满意,但上面的语法非常嘈杂。我希望能够更清楚地编写相同的代码,所以我决定写一个模式同义词:

pattern EqT :: forall b a. (Typeable a, Typeable b) => (a ~ b) => b -> a
pattern EqT x <- (viewEqT @b -> Just (Refl, x))

我认为我可以使用这种模式同义词来使我的邪恶案例分析更容易阅读:

evilId :: Typeable a => a -> a
evilId (EqT (n :: Int)) = n + 1
evilId (EqT (str :: String)) = reverse str
evilId x = x

可悲的是,这根本不起作用。在对模式进行类型检查之前,GHC似乎没有参考我的类型注释,因此它认为b在每个模式中都是一个模糊变量。有什么方法可以用模式同义词干净地包裹这些模式,还是我会被我的长视图模式困住?

1 个答案:

答案 0 :(得分:0)

如果目标是找到一些干净的语法来实现evilId函数,可以这样写:

{-# 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

不幸的是,这并没有帮助解决模式同义词的模糊性。