Lambda 函数的矛盾行为
Contradictory Behaviour of Lambda Functions
使用以下定义:
lenDigits n = length (show n)
factorial n = product [1..n]
我评价如下
Prelude> ((lenDigits . factorial) 199) <= 199
False
Prelude> (\i -> ((lenDigits . factorial) i) <= i) 199
True
这种行为的原因是什么?如我所见,第一个表达式与第二个表达式相同,只是减少了 lambda。
因为在第一个表达式中,第一个 199
的类型为 Integer
,第二个的类型为 Int
。但是在第二个表达式中,两者都具有类型 Int
并且 factorial 199
不能由类型 Int
.
表示
下面是对这个问题的逐步解答。
让我们开始:
((lenDigits . factorial) 199) <= 199
根据 Haskell Report...
An integer literal represents the application of the function fromInteger
to the appropriate value of type Integer
.
这意味着我们的第一个表达式实际上是:
((lenDigits . factorial) (fromInteger (199 :: Integer))
<= (fromInteger (199 :: Integer))
fromInteger (199 :: Integer)
本身具有多态类型 Num a => a
。我们现在必须查看此类型是否专门用于整个表达式的上下文。请注意,在我们找到不是这样的原因之前,我们应该假设两次出现的 fromInteger (199 :: Integer)
的多态类型是独立的(Num a => a
和 Num b => b
,如果你愿意的话) .
lenDigits
是 Show a => a -> Int
,所以...
(lenDigits . factorial) (fromInteger (199 :: Integer))
... <=
的左边必须是 Int
。鉴于 (<=)
是 Ord a => a -> a -> Bool
,<=
右边的 fromInteger (199 :: Integer)
也必须是 Int
。整个表达式变为:
((lenDigits . factorial) (fromInteger (199 :: Integer)) <= (199 :: Int)
虽然第二个 199
专用于 Int
,但第一个仍然是多态的。在没有其他类型注释的情况下,当我们在 GHCi 中使用表达式时,默认值使其专门化为 Integer
。因此,我们最终得到:
((lenDigits . factorial) (199 :: Integer)) <= (199 :: Int)
现在,进入第二个表达式:
(\i -> ((lenDigits . factorial) i) <= i) 199
根据上面使用的相同推理,(lenDigits . factorial) i
(<=
的左侧)是一个 Int
,因此 i
([= 的右侧) 28=]) 也是一个 Int
。既然如此,我们有...
GHCi> :t \i -> (lenDigits . factorial) i <= i
\i -> (lenDigits . factorial) i <= i :: Int -> Bool
... 因此将其应用于 199
(实际上是 fromInteger (199 :: Integer)
)将其专门化为 int,给出:
((lenDigits . factorial) (199 :: Int)) <= (199 :: Int)
第一个 199
现在是 Int
而不是 Integer
。 factorial (199 :: Int)
溢出固定大小的 Int
类型,导致虚假结果。避免这种情况的一种方法是引入显式 fromInteger
以获得与第一种情况等效的东西:
GHCi> :t \i -> (lenDigits . factorial) i <= fromInteger i
\i -> (lenDigits . factorial) i <= fromInteger i :: Integer -> Bool
GHCi> (\i -> (lenDigits . factorial) i <= fromInteger i) 199
False
使用以下定义:
lenDigits n = length (show n)
factorial n = product [1..n]
我评价如下
Prelude> ((lenDigits . factorial) 199) <= 199
False
Prelude> (\i -> ((lenDigits . factorial) i) <= i) 199
True
这种行为的原因是什么?如我所见,第一个表达式与第二个表达式相同,只是减少了 lambda。
因为在第一个表达式中,第一个 199
的类型为 Integer
,第二个的类型为 Int
。但是在第二个表达式中,两者都具有类型 Int
并且 factorial 199
不能由类型 Int
.
下面是对这个问题的逐步解答。
让我们开始:
((lenDigits . factorial) 199) <= 199
根据 Haskell Report...
An integer literal represents the application of the function
fromInteger
to the appropriate value of typeInteger
.
这意味着我们的第一个表达式实际上是:
((lenDigits . factorial) (fromInteger (199 :: Integer))
<= (fromInteger (199 :: Integer))
fromInteger (199 :: Integer)
本身具有多态类型 Num a => a
。我们现在必须查看此类型是否专门用于整个表达式的上下文。请注意,在我们找到不是这样的原因之前,我们应该假设两次出现的 fromInteger (199 :: Integer)
的多态类型是独立的(Num a => a
和 Num b => b
,如果你愿意的话) .
lenDigits
是 Show a => a -> Int
,所以...
(lenDigits . factorial) (fromInteger (199 :: Integer))
... <=
的左边必须是 Int
。鉴于 (<=)
是 Ord a => a -> a -> Bool
,<=
右边的 fromInteger (199 :: Integer)
也必须是 Int
。整个表达式变为:
((lenDigits . factorial) (fromInteger (199 :: Integer)) <= (199 :: Int)
虽然第二个 199
专用于 Int
,但第一个仍然是多态的。在没有其他类型注释的情况下,当我们在 GHCi 中使用表达式时,默认值使其专门化为 Integer
。因此,我们最终得到:
((lenDigits . factorial) (199 :: Integer)) <= (199 :: Int)
现在,进入第二个表达式:
(\i -> ((lenDigits . factorial) i) <= i) 199
根据上面使用的相同推理,(lenDigits . factorial) i
(<=
的左侧)是一个 Int
,因此 i
([= 的右侧) 28=]) 也是一个 Int
。既然如此,我们有...
GHCi> :t \i -> (lenDigits . factorial) i <= i
\i -> (lenDigits . factorial) i <= i :: Int -> Bool
... 因此将其应用于 199
(实际上是 fromInteger (199 :: Integer)
)将其专门化为 int,给出:
((lenDigits . factorial) (199 :: Int)) <= (199 :: Int)
第一个 199
现在是 Int
而不是 Integer
。 factorial (199 :: Int)
溢出固定大小的 Int
类型,导致虚假结果。避免这种情况的一种方法是引入显式 fromInteger
以获得与第一种情况等效的东西:
GHCi> :t \i -> (lenDigits . factorial) i <= fromInteger i
\i -> (lenDigits . factorial) i <= fromInteger i :: Integer -> Bool
GHCi> (\i -> (lenDigits . factorial) i <= fromInteger i) 199
False