Coerce幻影类型

时间:2014-02-08 17:43:18

标签: haskell types casting

我似乎已经陷入了一个有趣的边缘案例中。解释我想要做的事情很棘手,所以让我用代码写一下:

data Foobar x =
  Foo1 {field1 :: x, field2 :: String} |
  Foo2 {field1 :: x, field3 :: Int} |
  Foo3 {             field4 :: Bool} |
  Foo4 {             field2 :: String, field4 :: Bool}

正如您所看到的,某些构造函数依赖于x,但其他构造函数则不依赖fmap。我正在尝试编写类似于transform :: (x -> y) -> Foobar x -> Foobar y transform fn foobar = case foobar of Foo1 {} -> foobar {field1 = fn (field1 foobar)} Foo2 {} -> foobar {field1 = fn (field1 foobar)} _ -> foobar 的函数:

fn

正如您所看到的,记录语法整齐地让我避免重建整个构造函数,仅在需要的地方应用fn。不幸的是,当位置需要{{1}}时,这会中断。在那种情况下(即最后的替代方案),表达式无法进行类型检查。我很清楚为什么它失败了 - 但我对如何修复这一点感到困惑。

显然我可以直接写出整个事情。这适用于这个缩减的例子,但我想写的真正的应用程序要大得多。 (大约25个构造函数,其中一些构造函数超过15个。)

有没有人对如何解决这个故障有任何干净的想法?

2 个答案:

答案 0 :(得分:4)

一种解决方案(保存输入)是使用记录通配符:

{-# LANGUAGE RecordWildCards #-}
-- ...
case foobar of
   Foo4 {..} -> Foo4 {..}

答案 1 :(得分:2)

如果您不想手动执行此操作,则必须进行模式匹配。如果你想避免这么多的工作,一个简单的解决方法是

   {-# LANGUAGE DeriveFunctor #-}
   data Foo a = ...
     deriving(Functor)

现在我们可以写一个更安全的unsafeCoerce

形式
  coerceFoo :: Foo a -> Foo b
  coerceFoo = fmap (error "This shouldn't be used on a phantom type")

在你的例子中使用它

_       -> coerceFoo foobar
相关问题