首页 > 解决方案 > Haskell中的函数没有获得泛型类型参数

问题描述

在 Haskell 我有以下

data Box a = Box a deriving Show

instance Functor Box where
  fmap func (Box a) = Box (func a)

box :: Box Int
box = Box 8

wrapped :: Box (Box Int)
wrapped = Box <$> box

unwrap :: (Box a) -> a
unwrap (Box val) = val

在 GHCi 中,我可以调用fmapunwrap wrapped得到Box 8,这是我所期望的。

*Main> fmap unwrap wrapped
Box 8

当我打电话fmap时,unwrap box我得到关于类型不匹配的错误,但我想我会得到值 8。

*Main> fmap unwrap box

<interactive>:26:13: error:
    • Couldn't match type ‘Int’ with ‘Box b’
      Expected type: Box (Box b)
        Actual type: Box Int
    • In the second argument of ‘fmap’, namely ‘box’
      In the expression: fmap unwrap box
      In an equation for ‘it’: it = fmap unwrap box
    • Relevant bindings include
        it :: Box b (bound at <interactive>:26:1)

我原以为fmap unwrap box会给出价值8

我如何定义unwrap能够在使用时获得Box 8forwrapped8for的值?boxfmap

我认为这不重要,但我使用的是 GHCi 版本 8.8.4

标签: haskell

解决方案


如果你有 abox = Box 8并且想得到一个普通的8,你应该打电话unwrap box,而不是fmap unwrap box。一般来说,fmap永远不会让你解包一个值,因为它的类型(Functor f) => (a -> b) -> f a -> f b指定结果fmap x y将具有被包装的类型f b。让我们浏览一下这些类型,看看为什么会发生这种情况:

当我们调用 时,我们可以将 的类型与 的第一个参数的fmap unwrap类型“统一”起来,这为我们提供了这种特殊的类型:unwrapfmapfmap

fmap   :: (Functor f) => (a     -> b) -> f a       -> f b
unwrap ::                 Box a -> a
fmap   :: (Functor f) => (Box a -> a) -> f (Box a) -> f a

请注意,因为f没有出现在 的第一个参数的类型中fmapBox所以没有填写 for f。然后我们可以应用unwrap到这个专门的版本fmap

fmap unwrap :: (Functor f) => f (Box a) -> f a

这几乎肯定不是您在这里所期望的类型。当我们为参数统一这个时Box (Box 8),我们得到专门的类型:

fmap unwrap :: (Functor f) => f   (Box a  ) -> f   a
Box (Box 8) ::                Box (Box Int)
fmap unwrap ::                Box (Box Int) -> Box Int

但是当我们尝试将它与参数的类型统一起来时Box 8,我们遇到了一个问题:

fmap unwrap :: (Functor f) => f   (Box a) -> f   a
Box 8       ::                Box Int

我无法将 的类型Box 8与预期的参数匹配,fmap unwrap因为Int与 type 不匹配Box a


推荐阅读