我发现最简单的方法是使用 GHCi 7.8 中提供的typed holes:
> (*10) <$> _a $ 1
Found hole ‘_a’ with type: s0 -> b
Where: ‘s0’ is an ambiguous type variable
‘b’ is a rigid type variable bound by
the inferred type of it :: b at <interactive>:4:1
Relevant bindings include it :: b (bound at <interactive>:4:1)
In the second argument of ‘(<$>)’, namely ‘_a’
In the expression: (* 10) <$> _a
In the expression: (* 10) <$> _a $ 1
所以这告诉我a :: s0 -> b。接下来是弄清楚运算符的顺序:
> :i (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
infixl 4 <$>
> :i ($)
($) :: (a -> b) -> a -> b
infixr 0 $
所以这表示$ 是高度右关联的,并且鉴于它的类型,我们看到它的第一个参数必须是一个函数,所以a 必须是一个函数(双重确认)。这意味着(*10) <$> a $ 1 与((*10) <$> a) $ 1 相同,因此我们将首先关注(*10) <$> a。
> :t ((*10) <$>)
((*10) <$>) :: (Num a, Functor f) => f a -> f a
> :t (<$> _a)
Found hole ‘_a’ with type: f a
Where: ‘a’ is a rigid type variable bound by
the inferred type of it :: (a -> b) -> f b at Top level
‘f’ is a rigid type variable bound by
the inferred type of it :: (a -> b) -> f b at Top level
In the second argument of ‘(<$>)’, namely ‘_a’
In the expression: (<$> _a)
所以我们需要a 作为函子。有哪些可用实例?
> :i Functor
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
-- Defined in ‘GHC.Base’
instance Functor Maybe -- Defined in ‘Data.Maybe’
instance Functor (Either a) -- Defined in ‘Data.Either’
instance Functor ZipList -- Defined in ‘Control.Applicative’
instance Monad m => Functor (WrappedMonad m)
-- Defined in ‘Control.Applicative’
instance Control.Arrow.Arrow a => Functor (WrappedArrow a b)
-- Defined in ‘Control.Applicative’
instance Functor (Const m) -- Defined in ‘Control.Applicative’
instance Functor [] -- Defined in ‘GHC.Base’
instance Functor IO -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((,) a) -- Defined in ‘GHC.Base’
所以(->) r 恰好是一个,这太棒了,因为我们知道a 必须是一个函数。从Num 约束,我们可以确定r 必须与Num a => a 相同。这意味着(*10) <$> a :: Num a => a -> a。然后我们将1 应用到它上面,我们会得到(*10) <$> a $ 1 :: Num a,其中a 是一些未知函数。
所有这些都可以通过 GHCi 使用 :t 和 :i 以及键入的孔来发现。当然,这涉及到相当多的步骤,但是当您尝试分解复杂的表达式时,它永远不会失败,只需查看不同子表达式的类型即可。