Trên thực tế, có vẻ như fix (* 0) == 0
chỉ hoạt động cho Integer
, nếu bạn chạy fix (* 0) :: Double
hoặc fix (* 0) :: Int
, bạn vẫn nhận được ***Exception <<loop>>
Đó là bởi vì trong instance Num Integer
, (*)
được định nghĩa là (*) = timesInteger
timesInteger
được định nghĩa trong Data.Integer
-- | Multiply two 'Integer's
timesInteger :: Integer -> Integer -> Integer
timesInteger _ (S# 0#) = S# 0#
timesInteger (S# 0#) _ = S# 0#
timesInteger x (S# 1#) = x
timesInteger (S# 1#) y = y
timesInteger x (S# -1#) = negateInteger x
timesInteger (S# -1#) y = negateInteger y
timesInteger (S# x#) (S# y#)
= case mulIntMayOflo# x# y# of
0# -> S# (x# *# y#)
_ -> timesInt2Integer x# y#
timesInteger [email protected](S# _) y = timesInteger y x
-- no S# as first arg from here on
timesInteger (Jp# x) (Jp# y) = Jp# (timesBigNat x y)
timesInteger (Jp# x) (Jn# y) = Jn# (timesBigNat x y)
timesInteger (Jp# x) (S# y#)
| isTrue# (y# >=# 0#) = Jp# (timesBigNatWord x (int2Word# y#))
| True = Jn# (timesBigNatWord x (int2Word# (negateInt# y#)))
timesInteger (Jn# x) (Jn# y) = Jp# (timesBigNat x y)
timesInteger (Jn# x) (Jp# y) = Jn# (timesBigNat x y)
timesInteger (Jn# x) (S# y#)
| isTrue# (y# >=# 0#) = Jn# (timesBigNatWord x (int2Word# y#))
| True = Jp# (timesBigNatWord x (int2Word# (negateInt# y#)))
Nhìn vào con cá tuyết trên e, nếu bạn chạy (* 0) x
, sau đó timesInteger _ (S# 0#)
sẽ phù hợp để x
sẽ không được đánh giá, trong khi nếu bạn chạy (0 *) x
, sau đó khi kiểm tra xem timesInteger _ (S# 0#)
trận đấu, x sẽ được đánh giá và gây ra vòng lặp vô hạn
Chúng ta có thể sử dụng dưới mã để kiểm tra nó:
module Test where
import Data.Function(fix)
-- fix (0 ~*) == 0
-- fix (~* 0) == ***Exception<<loop>>
(~*) :: (Num a, Eq a) => a -> a -> a
0 ~* _ = 0
_ ~* 0 = 0
x ~* y = x ~* y
-- fix (0 *~) == ***Exception<<loop>>
-- fix (*~ 0) == 0
(*~) :: (Num a, Eq a) => a -> a -> a
_ *~ 0 = 0
0 *~ _ = 0
x *~ y = x *~ y
có một cái gì đó thậm chí thú vị hơn, trong GHCI:
*Test> let x = fix (* 0)
*Test> x
0
*Test> x :: Double
*** Exception: <<loop>>
*Test>
gÌ? Thật tuyệt vời! – PyRulez
Đây là * chính xác * điểm làm cho [ngữ nghĩa biểu thị] (https://en.wikipedia.org/wiki/Denotational_semantics) không hoàn toàn tương đương với [ngữ nghĩa hoạt động] (https://en.wikipedia.org/wiki/ Operational_semantics), tức là không hoàn toàn trừu tượng. Cái trước có thể biểu diễn một hàm 'f' với' f undefined 0 = 0' và 'f 0 undefined = 0' trong khi hàm thứ hai không thể. Việc triển khai ngôn ngữ tuân theo ngữ nghĩa hoạt động, do đó làm cho nó không thể định nghĩa một 'f' mà không có một số thủ thuật. – Bakuriu