我通过了Paul Hudaks强烈推荐的书Haskell School of Expression。 在第13章中,我偶然发现了这个定义
type Time = Float
newtype Behavior a = Beh (Time -> a)
作者已声明了新类型Behavior
的几个实例:Eq
,Show
,Num
,Fractional
和Floating
,但是这些只是其中一个实例声明中的一个函数,它困扰着我:
instance Num a => Num (Behavior a) where
(+) = lift2 (+) -- This one!
fromInteger = lift0 . fromInteger
lift0 :: a -> Behavior a
lift0 x = Beh (\t -> x)
lift2 :: (a -> b -> c) -> (Behavior a -> Behavior b -> Behavior c)
lift2 g (Beh a) (Beh b)
= Beh (\t -> g (a t) (b t)) -- Or actually this one.
time :: Behavior Time
time = Beh (\t -> t)
在此之后,作者描述了使用这些新的函数声明,我们现在可以编写time + 5
,从而将(+)
运算符提升到行为领域,或以某种方式提升。这对我来说听起来很好,所以当我读书时,我点头微笑。突然,作者解释说:(time + 5)
相当于Beh (\t -> t + 5)
,这听起来完全被打破了。他实际上甚至提供了表达式的展开来证明它:
time + 5
==> { unfold overloadings for time, (+), and 5 }
(lift2 (+)) (Beh (\t -> t)) (Beh (\t -> 5))
==> { unfold lift2 }
(\ (Beh a) (Beh b) -> Beh (\t -> a t + b t)) (Beh (\t -> t)) (Beh (\t -> 5))
==> { unfold anonymous function }
Beh (\t -> (\t -> t) t + (\t -> 5) t )
==> { unfold two anonymous functions }
Beh (\t -> t + 5)
这更具体地说是我理解上的问题。对我来说,正确的陈述是:time + (Beh 5)
等同于Beh (\t -> t + 5)
。但是当我推断ghci中的类型时,它(当然)告诉我作者是正确的,并且我以某种正式方式愚蠢。有人可以向我解释一下。
答案 0 :(得分:5)
(+)
的类型为Num a => a -> a -> a
。此处a
为Behavior Float
。代码中的文字5
将Behavior Float
转换为fromInteger
,其fromInteger n = Beh (\t -> fromInteger n)
应为Beh 5
。
Beh
不会进行类型检查,因为Float -> a
包含了{{1}}类型的函数,而不是数字。