美文网首页
haskell + 加号是中缀函数? 编译器内求证下

haskell + 加号是中缀函数? 编译器内求证下

作者: onedam | 来源:发表于2020-05-20 23:50 被阅读0次

加号在 c java 等语言内都是 内置的操作计算符, java 还把+号 重载到可以 字符串拼接.
但在clojure 中可以明确的找到 + 号的函数定义,(还是前缀表示)

(defn +
  "Returns the sum of nums. (+) returns 0. Does not auto-promote
  longs, will throw on overflow. See also: +'"
  {:inline (nary-inline 'add 'unchecked_add)
   :inline-arities >1?
   :added "1.2"}
  ([] 0)
  ([x] (cast Number x))
  ([x y] (. clojure.lang.Numbers (add x y)))
  ([x y & more]
     (reduce1 + (+ x y) more)))

在haskell中竟然有中缀函数的概念. + 号是函数 是定义在 Num.hs中的

class  Num a  where
    {-# MINIMAL (+), (*), abs, signum, fromInteger, (negate | (-)) #-}

    (+), (-), (*)       :: a -> a -> a
    -- | Unary negation.
    negate              :: a -> a
    -- | Absolute value.
    abs                 :: a -> a
    -- | Sign of a number.
    -- The functions 'abs' and 'signum' should satisfy the law:
    --
    -- > abs x * signum x == x
    --
    -- For real numbers, the 'signum' is either @-1@ (negative), @0@ (zero)
    -- or @1@ (positive).
    signum              :: a -> a
    -- | Conversion from an 'Integer'.
    -- An integer literal represents the application of the function
    -- 'fromInteger' to the appropriate value of type 'Integer',
    -- so such literals have type @('Num' a) => a@.
    fromInteger         :: Integer -> a

    {-# INLINE (-) #-}
    {-# INLINE negate #-}
    x - y               = x + negate y
    negate x            = 0 - x

-- | the same as @'flip' ('-')@.
--
-- Because @-@ is treated specially in the Haskell grammar,
-- @(-@ /e/@)@ is not a section, but an application of prefix negation.
-- However, @('subtract'@ /exp/@)@ is equivalent to the disallowed section.
{-# INLINE subtract #-}
subtract :: (Num a) => a -> a -> a
subtract x y = y - x

-- | @since 2.01
instance  Num Int  where
    I# x + I# y = I# (x +# y)
    I# x - I# y = I# (x -# y)
    negate (I# x) = I# (negateInt# x)
    I# x * I# y = I# (x *# y)
    abs n  = if n `geInt` 0 then n else negate n

    signum n | n `ltInt` 0 = negate 1
             | n `eqInt` 0 = 0
             | otherwise   = 1

    {-# INLINE fromInteger #-}   -- Just to be sure!
    fromInteger i = I# (integerToInt i)

-- | @since 2.01
instance Num Word where
    (W# x#) + (W# y#)      = W# (x# `plusWord#` y#)
    (W# x#) - (W# y#)      = W# (x# `minusWord#` y#)
    (W# x#) * (W# y#)      = W# (x# `timesWord#` y#)
    negate (W# x#)         = W# (int2Word# (negateInt# (word2Int# x#)))
    abs x                  = x
    signum 0               = 0
    signum _               = 1
    fromInteger i          = W# (integerToWord i)

-- | @since 2.01
instance  Num Integer  where
    (+) = plusInteger
    (-) = minusInteger
    (*) = timesInteger
    negate         = negateInteger
    fromInteger x  =  x

    abs = absInteger
    signum = signumInteger

研究下其中 plusInteger 的来源,其定义在 ghc 源码
/libraries/integer-simple/GHC/Integer/Type.hs 343行

{-# NOINLINE plusInteger #-}
plusInteger :: Integer -> Integer -> Integer
Positive p1    `plusInteger` Positive p2 = Positive (p1 `plusPositive` p2)
Negative p1    `plusInteger` Negative p2 = Negative (p1 `plusPositive` p2)
Positive p1    `plusInteger` Negative p2
    = case p1 `comparePositive` p2 of
      GT -> Positive (p1 `minusPositive` p2)
      EQ -> Naught
      LT -> Negative (p2 `minusPositive` p1)
Negative p1    `plusInteger` Positive p2
    = Positive p2 `plusInteger` Negative p1
Naught         `plusInteger` Naught         = Naught
Naught         `plusInteger` i@(Positive _) = i
Naught         `plusInteger` i@(Negative _) = i
i@(Positive _) `plusInteger` Naught         = i
i@(Negative _) `plusInteger` Naught         = i

继续追踪 plusPositive 还是在这个文件的 580 行

plusPositive :: Positive -> Positive -> Positive
plusPositive x0 y0 = addWithCarry 0## x0 y0
where -- digit `elem` [0, 1]
      -- Note [Avoid patError]
      addWithCarry :: Digit -> Positive -> Positive -> Positive
      addWithCarry c None            None            = addOnCarry c None
      addWithCarry c xs@(Some {})    None            = addOnCarry c xs
      addWithCarry c None            ys@(Some {})    = addOnCarry c ys
      addWithCarry c xs@(Some x xs') ys@(Some y ys')
       = if isTrue# (x `ltWord#` y) then addWithCarry c ys xs
         -- Now x >= y
         else if isTrue# (y `geWord#` halfBoundUp ())
              -- So they are both at least halfBoundUp, so we subtract
              -- halfBoundUp from each and thus carry 1
              then case x `minusWord#` halfBoundUp () of
                   x' ->
                    case y `minusWord#` halfBoundUp () of
                    y' ->
                     case x' `plusWord#` y' `plusWord#` c of
                     this ->
                      Some this withCarry
         else if isTrue# (x `geWord#` halfBoundUp ())
              then case x `minusWord#` halfBoundUp () of
                   x' ->
                    case x' `plusWord#` y `plusWord#` c of
                    z ->
                     -- We've taken off halfBoundUp, so now we need to
                     -- add it back on
                     if isTrue# (z `ltWord#` halfBoundUp ())
                      then Some (z `plusWord#`  halfBoundUp ()) withoutCarry
                      else Some (z `minusWord#` halfBoundUp ()) withCarry
         else Some (x `plusWord#` y `plusWord#` c) withoutCarry
          where withCarry    = addWithCarry 1## xs' ys'
                withoutCarry = addWithCarry 0## xs' ys'

      -- digit `elem` [0, 1]
      addOnCarry :: Digit -> Positive -> Positive
      addOnCarry (!c) (!ws) = if isTrue# (c `eqWord#` 0##)
                              then ws
                              else succPositive ws

继续追踪 plusWord# 这次和上面的不同,竟然在hs文件中找不到定义. 在
compiler/GHC/Builtin/primops.txt.pp
这里找到了. 原来haskell中真正执行加法的在这里. 那这个文件有什么用呢? 这个文件把primitive operations (原始操作列到这里.) hadrian/src/Rules/Generate.hs 生成相应的代码(没有继续研究)

primop   WordAddOp   "plusWord#"   Dyadic   Word# -> Word# -> Word# 

上面我们看到他是生成了 WordAddOp 的haskell 函数 我们继续寻找下 . [compiler/GHC/StgToCmm/Prim.hs 这个文件中有与平台无关的明确描述 1120行

 WordAddOp      -> \args -> opTranslate args (mo_wordAdd platform)  

接着在 /compiler/GHC/Cmm/MachOp.hs 中发现 181 行

mo_wordAdd      platform = MO_Add (wordWidth platform)  --与平台相关了. haskell是支持多平台的

StgToCmm

/GHC/CmmToAsm/SPARC/CodeGen.hs

CmmToAsm

compiler/GHC/CmmToAsm/X86/CodeGen.hs
在这个x86平台生成代码的时候 调用了 *MO_Add *

-- Turn (lit1 << n  + lit2) into  (lit2 + lit1 << n) so it will be
-- recognised by the next rule.
getAmode' is32Bit (CmmMachOp (MO_Add rep) [a@(CmmMachOp (MO_Shl _) _),
                                  b@(CmmLit _)])
  = getAmode' is32Bit (CmmMachOp (MO_Add rep) [b,a])

(就这样. 先整根烟吧) . 加法 与 + 字符 在haskell中是个什么东西,有个大概认识了..

相关文章

网友评论

      本文标题:haskell + 加号是中缀函数? 编译器内求证下

      本文链接:https://www.haomeiwen.com/subject/dtaoohtx.html