简体   繁体   English

链接Haskell函数的数据类型

[英]Chaining Haskell Functions in data types

Lets say I have the following: 可以说我有以下内容:

data FuncAndValue v res = FuncAndValue (v -> res) v

chain :: (res -> new_res) -> FuncAndValue v res -> FuncAndValue v new_res
chain new_f (FuncAndValue old_f v) = FuncAndValue (new_f . old_f) v  

Is GHC likely to be able to combine functions new_f and old_f into a single function through inlining? GHC是否可以通过内联将函数new_fold_f成单个函数?

Basically, does storing functions in data types in anyway inhibit optimizations. 基本上,以数据类型存储函数无论如何都会抑制优化。

I'd like GHC to be easily able to compose chains of functions into one (ie so a "sum" on my structure doesn't involve repeated calls to a thunk that represents (+) and instead just inlines the (+) so it runs like a for loop. I'm hoping storing functions in data types and then accessing them later doesn't inhibit this. 我希望GHC能够轻松地将函数链组合成一个(也就是说,我的结构上的“总和”不涉及重复调用表示(+)的thunk,而只是内联(+)所以它像for循环一样运行。我希望将函数存储在数据类型中,然后稍后访问它们不会抑制它。

Is GHC likely to be able to combine functions new_f and old_f into a single function through inlining? GHC是否可以通过内联将函数new_fold_f成单个函数?

Yes, if it could do the same without the intervening FuncAndValue . 是的,如果没有介入的FuncAndValue可以做同样的FuncAndValue Of course the unfoldings of the functions need to be available, or there wouldn't be any chance of inlining anyway. 当然,需要提供功能的展开,或者无论如何也不会有任何内联的机会。 But if there is a chance, wrapping the function(s) in a FuncAndValue makes little difference if any. 但是如果有可能的话,将函数包装在FuncAndValue就没什么区别了。

But let's ask GHC itself. 但是让我们问一下GHC本身。 First the type and a very simple chain ing: 首先是类型和非常简单的chain

module FuncAndValue where

data FuncAndValue v res = FuncAndValue (v -> res) v

infixr 7 `chain`

chain :: (res -> new_res) -> FuncAndValue v res -> FuncAndValue v new_res
chain new_f (FuncAndValue old_f v) = FuncAndValue (new_f . old_f) v

apply :: FuncAndValue v res -> res
apply (FuncAndValue f x) = f x

trivia :: FuncAndValue Int (Int,Int)
trivia = FuncAndValue (\x -> (2*x - 1, 3*x + 2)) 1

composed :: FuncAndValue Int Int
composed = chain (uncurry (+)) trivia

and (the interesting part of) the core we get for trivia and composed : 和(有趣的部分)我们得到的triviacomposed的核心:

FuncAndValue.trivia1 =
  \ (x_af2 :: GHC.Types.Int) ->
    (case x_af2 of _ { GHC.Types.I# y_agp ->
     GHC.Types.I# (GHC.Prim.-# (GHC.Prim.*# 2 y_agp) 1)
     },
     case x_af2 of _ { GHC.Types.I# y_agp ->
     GHC.Types.I# (GHC.Prim.+# (GHC.Prim.*# 3 y_agp) 2)
     })

FuncAndValue.composed2 =
  \ (x_agg :: GHC.Types.Int) ->
    case x_agg of _ { GHC.Types.I# y_agp ->
    GHC.Types.I#
      (GHC.Prim.+#
         (GHC.Prim.-# (GHC.Prim.*# 2 y_agp) 1)
         (GHC.Prim.+# (GHC.Prim.*# 3 y_agp) 2))
    }

Inlined fair enough, no (.) to be seen. 内联公平,没有(.)可见。 The two case s from trivia have been joined so that we have only one in composed . 来自trivia的两个case已经加入,因此我们只有一个composed Unless somebody teaches GHC enough algebra to simplify \\x -> (2*x-1) + (3*x+2) to \\x -> 5*x + 1 , that's as good as you can hope. 除非有人教GHC足够的代数来简化\\x -> (2*x-1) + (3*x+2)\\x -> 5*x + 1 ,这就像你希望的那样好。 apply composed is reduced to 6 at compile time, even in a separate module. apply composed编译在编译时减少到6 ,即使在单独的模块中也是如此。

But that was very simple, let's give it a somewhat harder nut to crack. 但这简单,让我们给它一个更难解决的难题。

An inlinable version of until (the current definition of until is recursive, so GHC doesn't inline it), 一个可以内联版本until (目前的定义until是递归的,所以GHC不内联的话),

module WWUntil where

wwUntil :: (a -> Bool) -> (a -> a) -> a -> a
wwUntil p f = recur
  where
    recur x
        | p x       = x
        | otherwise = recur (f x)

Another simple function it its own module, 另一个简单的功能是它自己的模块,

collatzStep :: Int -> Int
collatzStep n
    | n .&. 1 == 0  = n `unsafeShiftR` 1
    | otherwise     = 3*n + 1

and finally, the nut 最后,坚果

module Hailstone (collatzLength, hailstone) where

import FuncAndValue
import CollatzStep
import WWUntil

data P = P {-# UNPACK #-} !Int {-# UNPACK #-} !Int

fstP :: P -> Int
fstP (P x _) = x

sndP :: P -> Int
sndP (P _ y) = y

hailstone :: Int -> FuncAndValue Int Int
hailstone n = sndP `chain` wwUntil ((== 1) . fstP) (\(P n k) -> P (collatzStep n) (k+1))
                   `chain` FuncAndValue (\x -> P x 0) n

collatzLength :: Int -> Int
collatzLength = apply . hailstone

I have helped the strictness analyser a bit by using a strict pair. 我使用严格的一对帮助了严格性分析器。 With the vanilla (,) the second component would be unboxed and reboxed after adding 1 in each step, and I just can't bear such waste ;) But otherwise there's no relevant difference. 使用香草(,) ,第二个组件将在每个步骤中添加1后取消装箱并重新装箱,我不能忍受这样的浪费;)但是否则没有相关的区别。

And (the interesting part of) the core GHC generates: 核心GHC的(有趣的部分)产生:

Rec {
Hailstone.$wrecur [Occ=LoopBreaker]
  :: GHC.Prim.Int#
     -> GHC.Prim.Int# -> (# GHC.Prim.Int#, GHC.Prim.Int# #)
[GblId, Arity=2, Caf=NoCafRefs, Str=DmdType LL]
Hailstone.$wrecur =
  \ (ww_sqq :: GHC.Prim.Int#) (ww1_sqr :: GHC.Prim.Int#) ->
    case ww_sqq of wild_Xm {
      __DEFAULT ->
        case GHC.Prim.word2Int#
               (GHC.Prim.and# (GHC.Prim.int2Word# wild_Xm) (__word 1))
        of _ {
          __DEFAULT ->
            Hailstone.$wrecur
              (GHC.Prim.+# (GHC.Prim.*# 3 wild_Xm) 1) (GHC.Prim.+# ww1_sqr 1);
          0 ->
            Hailstone.$wrecur
              (GHC.Prim.uncheckedIShiftRA# wild_Xm 1) (GHC.Prim.+# ww1_sqr 1)
        };
      1 -> (# 1, ww1_sqr #)
    }
end Rec }

lvl_rsz :: GHC.Types.Int -> GHC.Types.Int
[GblId, Arity=1, Caf=NoCafRefs]
lvl_rsz =
  \ (x_iog :: GHC.Types.Int) ->
    case x_iog of _ { GHC.Types.I# tpl1_B4 ->
    case Hailstone.$wrecur tpl1_B4 0 of _ { (# _, ww2_sqH #) ->
    GHC.Types.I# ww2_sqH
    }
    }

and that's exactly what you get without FuncAndValue . 而这正是你在没有FuncAndValue情况下FuncAndValue Everything inlined nicely, a beautiful tight loop. 一切都很好地勾勒出一个美丽的紧凑循环。

Basically, does storing functions in data types in anyway inhibit optimizations. 基本上,以数据类型存储函数无论如何都会抑制优化。

If you wrap the function under enough layers, yes. 如果将函数包装在足够的图层下,是的。 But it's the same with other values. 但它与其他价值观相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM