- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我真的很喜欢以通用方式处理变形/变形的想法,但在我看来它有一个显着的性能缺陷:
假设我们想要以分类方式使用树结构 - 使用通用 catamorphism function 来描述不同的折叠:
newtype Fix f = Fix { unfix :: f (Fix f) }
data TreeT r = Leaf | Tree r r
instance Functor TreeT where
fmap f Leaf = Leaf
fmap f (Tree l r) = Tree (f l) (f r)
type Tree = Fix TreeT
catam :: (Functor f) => (f a -> a) -> (Fix f -> a)
catam f = f . fmap (catam f) . unfix
现在我们可以编写如下函数:
depth1 :: Tree -> Int
depth1 = catam g
where
g Leaf = 0
g (Tree l r) = max l r
不幸的是,这种方法有一个显着的缺点:在计算过程中,TreeT Int
的新实例会在 fmap
的每个级别创建,以便立即被 使用>g
。与经典定义相比
depth2 :: Tree -> Int
depth2 (Fix Leaf) = 0
depth2 (Fix (Tree l r)) = max (depth1 l) (depth1 r)
我们的深度1
总是会变慢,给GC带来不必要的压力。一种解决方案是使用 hylomorphisms并将创造树和折叠树结合在一起。但通常我们不想这样做,我们可能希望在一个地方创建一棵树,然后传递到其他地方以便稍后折叠。或者,以不同的变形来多次文件夹。
有没有办法让GHC优化深度1
?类似于内联 catam g
然后 fusing/deforesting g . fmap ...
里面?
最佳答案
我相信我找到了答案。我记得读过Why does GHC make fix so confounding?这给了我一个解决方案。
catam
之前定义的问题在于它是递归的,因此任何尝试 INLINE它被忽略了。使用 -ddump-simpl -ddump-to-file
编译原始版本并读取 core :
Main.depth1 = Main.catam_$scatam @ GHC.Types.Int Main.depth3
Main.depth3 =
\ (ds_dyI :: Main.TreeT GHC.Types.Int) ->
case ds_dyI of _ {
Main.Leaf -> Main.depth4;
Main.Tree l_aah r_aai -> GHC.Classes.$fOrdInt_$cmax l_aah r_aai
}
Main.depth4 = GHC.Types.I# 0
Rec {
Main.catam_$scatam =
\ (@ a_ajB)
(eta_B1 :: Main.TreeT a_ajB -> a_ajB)
(eta1_X2 :: Main.Fix Main.TreeT) ->
eta_B1
(case eta1_X2
`cast` (Main.NTCo:Fix <Main.TreeT>
:: Main.Fix Main.TreeT ~# Main.TreeT (Main.Fix Main.TreeT))
of _ {
Main.Leaf -> Main.Leaf @ a_ajB;
Main.Tree l_aan r_aao ->
Main.Tree
@ a_ajB
(Main.catam_$scatam @ a_ajB eta_B1 l_aan)
(Main.catam_$scatam @ a_ajB eta_B1 r_aao)
})
end Rec }
与
相比,
显然更糟糕(catam_$scatam
中的构造函数创建/消除,更多的函数调用)
Main.depth2 =
\ (w_s1Rz :: Main.Tree) ->
case Main.$wdepth2 w_s1Rz of ww_s1RC { __DEFAULT ->
GHC.Types.I# ww_s1RC
}
Rec {
Main.$wdepth2 [Occ=LoopBreaker] :: Main.Tree -> GHC.Prim.Int#
[GblId, Arity=1, Caf=NoCafRefs, Str=DmdType S]
Main.$wdepth2 =
\ (w_s1Rz :: Main.Tree) ->
case w_s1Rz
`cast` (Main.NTCo:Fix <Main.TreeT>
:: Main.Fix Main.TreeT ~# Main.TreeT (Main.Fix Main.TreeT))
of _ {
Main.Leaf -> 0;
Main.Tree l_aaj r_aak ->
case Main.$wdepth2 l_aaj of ww_s1RC { __DEFAULT ->
case Main.$wdepth2 r_aak of ww1_X1Sh { __DEFAULT ->
case GHC.Prim.<=# ww_s1RC ww1_X1Sh of _ {
GHC.Types.False -> ww_s1RC;
GHC.Types.True -> ww1_X1Sh
}
}
}
}
end Rec }
但是如果我们将catam
定义为
{-# INLINE catam #-}
catam :: (Functor f) => (f a -> a) -> (Fix f -> a)
catam f = let u = f . fmap u . unfix
in u
那么它就不再是递归的,只有里面的u
是递归的。这样,GHC 将 catam
内联到 depth1
的定义中,并将 fmap
与 depth1
的 g
- 正是我们想要的:
Main.depth1 =
\ (w_s1RJ :: Main.Tree) ->
case Main.$wdepth1 w_s1RJ of ww_s1RM { __DEFAULT ->
GHC.Types.I# ww_s1RM
}
Rec {
Main.$wdepth1 [Occ=LoopBreaker] :: Main.Tree -> GHC.Prim.Int#
[GblId, Arity=1, Caf=NoCafRefs, Str=DmdType S]
Main.$wdepth1 =
\ (w_s1RJ :: Main.Tree) ->
case w_s1RJ
`cast` (Main.NTCo:Fix <Main.TreeT>
:: Main.Fix Main.TreeT ~# Main.TreeT (Main.Fix Main.TreeT))
of _ {
Main.Leaf -> 0;
Main.Tree l_aar r_aas ->
case Main.$wdepth1 l_aar of ww_s1RM { __DEFAULT ->
case Main.$wdepth1 r_aas of ww1_X1So { __DEFAULT ->
case GHC.Prim.<=# ww_s1RM ww1_X1So of _ {
GHC.Types.False -> ww_s1RM;
GHC.Types.True -> ww1_X1So
}
}
}
}
end Rec }
现在与 深度2
的转储相同。
关于optimization - 是否有可能使 GHC 优化(砍伐)通用功能,例如变形?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13099203/
降本手段一招鲜,增效方法吃遍天; 01 互联网行业里; 降本策略千奇百怪,手段却出奇一致;增效方法五花八门,手段更是花里胡哨; 对于企业来说;
有什么方法可以使用 angularjs 中的部分进行代码分组吗? 原因 --- 我的 Controller 包含太多代码。该 Controller 包含了多个方法和大量功能的代码,降低了代码的可读性。
不幸的是,我的数据库的数据模型必须改变,所以我正在寻找最轻松的方式来迁移我的数据。 此时情况如何: create table cargo{ id serial primary key, per
在 QTextEdit 对象中,假设我想知道字符在鼠标光标下的位置。 我会写... void MyQTextEditObject::mousePressEvent(QMouseEvent* mouse
是否可以在 C++ 中返回一个 return 语句或做一些具有类似功能的事情? 例如,如果代码中有几个函数将指针作为输入,并且每个函数都检查指针是否为 nullptr,这将很方便。如果它是一个 nul
我的 PC 上有一个控制台应用程序,它是 signalR 服务器。 我有一个 html 页面,它是互联网上的 signalR 客户端。但我尝试连接服务器,但我有一个错误的请求 400 错误。如果服务器
我想将应用程序作为后台进程运行。当点击应用程序图标时,它不会显示任何 View ,只会启动后台进程。 最佳答案 对于 iOS 这是不可能的,但是对于 android,react native 有 he
我知道有(昂贵的)框架可以让你在 VS C# 中编写 android 应用程序并将其编译为 android apk。 我也知道,可以在 VS 中编写 Java 应用程序(link)。 是否有可能,甚至
我在做: can :manage, :all if user.role == 'admin' can :approve, Anuncio do |anuncio| anuncio.try(:apr
我是一名优秀的程序员,十分优秀!