Haskell 中的函子:显示类型参数类型的项的值

Lea*_*... 5 haskell

GHC 不知道如何显示类型 a。

data FunctorExample a = FunctorExample { val1 :: a, 
                                         val2 :: String
                                        } deriving (Show) 

instance Functor FunctorExample where
    fmap f (FunctorExample x y) = FunctorExample (f x) (y ++ " " ++ show x)
Run Code Online (Sandbox Code Playgroud)

我尝试了很多事情,包括:在数据中设置类型约束(现已弃用),并使用 {-# LANGUAGE InstanceSigs #-} 为 fmap 添加约束并添加下面建议的类型签名,但没有成功(虽然我的类型签名可能有缺陷......)。

    * No instance for (Show a) arising from a use of `show'
      Possible fix:
        add (Show a) to the context of
          the type signature for:
            fmap :: forall a b.
                    (a -> b) -> FunctorExample a -> FunctorExample b
Run Code Online (Sandbox Code Playgroud)

是否没有将 a 限制为 Show 实例的标准方法?在我的用法中,它碰巧总是一个 Int 。

Tre*_*edJ 5

免责声明:如果我犯了任何错误或以不同的方式处理问题,请原谅我,我自己也是 Haskell 学习者。

我想指出的第一件事是你的定义fmap不符合两个函子定律。这些规律的存在使得“行为fmap仍然是可预测的”。

第一定律指出fmap id functor应该与id functor(即fmap id = id)没有区别。只需观察定义,我们就可以看到:

fmap id (FunctorExample x y) = FunctorExample (id x) (y ++ ...)
Run Code Online (Sandbox Code Playgroud)

...不会飞,因为第二个的值y很容易改变。

第二定律指出fmap (f . g) = fmap f . fmap g。我将把它留给你作为练习来检查它是否符合。

我在这里建议的是使用不同的函数,这样就没有遵守函子定律的负担。这样,您就可以使用类型类约束。

propagate :: Show a => (a -> b) -> FunctorExample a -> FunctorExample b
propagate f (FunctorExample x y) = FunctorExample (f x) (y ++ " " ++ show x)
Run Code Online (Sandbox Code Playgroud)

现在,也许您对fmap. 我不完全确定。也许您打算FunctorExample在其他带有函子的函数中使用。(我猜是这个名字。)如果是这样,请考虑重新设计fmap定义,使其符合函子定律。

澄清一下,限制 的类型fmap 是不可能的