无法为ADT

时间:2015-06-01 17:12:10

标签: haskell

我正在开发一个将二进制格式解析为Haskell值的库。第一步创建一个ADT,它通过某些原始值提供额外的类型信息。我在下面写了一个简化版本Object

我希望该库的用户将此值视为Functor,或者使用其他方法从结构中提取值。我无法为Functor编写有效的Object实例。是否可以这样做?

data Object a
  = N
  | B Bool
  | I Int
  | L [Object a]
  deriving (Eq, Show)

instance Functor Object where
  fmap f N     = N
  fmap f (B x) = B $ f x
  -- etc.

-- GHC error.

-- % ghci Object.hs
-- GHCi, version 7.10.1: http://www.haskell.org/ghc/  :? for help
-- [1 of 1] Compiling Main             ( Object.hs, interpreted )

-- Object.hs:10:22:
--     Couldn't match expected type ‘Bool’ with actual type ‘b’
--       ‘b’ is a rigid type variable bound by
--           the type signature for fmap :: (a -> b) -> Object a -> Object b
--           at Object.hs:9:3
--     Relevant bindings include
--       f :: a -> b (bound at Object.hs:10:8)
--       fmap :: (a -> b) -> Object a -> Object b (bound at Object.hs:9:3)
--     In the second argument of ‘($)’, namely ‘f x’
--     In the expression: B $ f x

-- Object.hs:10:24:
--     Couldn't match expected type ‘a’ with actual type ‘Bool’
--       ‘a’ is a rigid type variable bound by
--           the type signature for fmap :: (a -> b) -> Object a -> Object b
--           at Object.hs:9:3
--     Relevant bindings include
--       f :: a -> b (bound at Object.hs:10:8)
--       fmap :: (a -> b) -> Object a -> Object b (bound at Object.hs:9:3)
--     In the first argument of ‘f’, namely ‘x’
--     In the second argument of ‘($)’, namely ‘f x’
-- Failed, modules loaded: none.
-- Prelude>

1 个答案:

答案 0 :(得分:1)

您可以使用

instance Functor Object where
  fmap f N     = N
  fmap f (B x) = B x
  fmap f (I i) = I i
  fmap f (L xs) = L $ map (fmap f) xs

或者更简单地说:

data Object a
  = N
  | B Bool
  | I Int
  | L [Object a]
  deriving (Eq, Show, Functor)
启用DeriveFunctor扩展程序后

请注意,您的a未在任何地方使用,因此Object a为幻像类型。这是故意的吗? 因此,您无法将f真正应用于任何内容,因为您需要类型为a的值。您正尝试将f应用于Bool的固定类型,但这不会进行类型检查,因为f的类型为a -> b,其中{{1}是a中的a,不一定是Object a