- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图找到 GHC 中发生的某种内联的来源,其中作为参数传递给另一个函数的函数是内联的。例如,我可能会编写如下定义(使用我自己的 List 类型来避免重写规则):
data MyList a = Nil | Cons a (MyList a)
deriving (Show)
mapMyList :: (a -> b) -> MyList a -> MyList b
mapMyList f Nil = Nil
mapMyList f (Cons a rest) = Cons (f a) $ mapMyList f rest
接电话
fromList :: [a] -> MyList a
fromList = ...
main = do
print $ mapMyList (*2) $ fromList [1..5]
mapMyList
是递归的,所以它不能直接内联。但是,在生成的核心中,我看到了以下定义:
Rec {
-- RHS size: {terms: 16, types: 11, coercions: 0, joins: 0/0}
Main.main_$smapMyList [Occ=LoopBreaker] :: MyList Int -> MyList Int
[GblId, Arity=1, Str=<S,1*U>, Unf=OtherCon []]
Main.main_$smapMyList
= \ (sc_s2Rb :: MyList Int) ->
case sc_s2Rb of {
Nil -> Main.Nil @Int;
Cons a_aBe rest_aBf ->
Main.Cons
@Int
(case a_aBe of { GHC.Types.I# x_a24u ->
GHC.Types.I# (GHC.Prim.*# x_a24u 2#)
})
(Main.main_$smapMyList rest_aBf)
}
end Rec }
特别是,
smapMyList
不再将函数作为参数,
(* 2)
在这里内联。我想知道哪个优化 channel 正在生成此代码,以及它是如何工作的?
May be seen as removing invariants from loops:Arguments of recursive functions that do not change in recursivecalls are removed from the recursion, which is done locallyand only passes the arguments which effectively change.
-fno-static-argument-transformation -fno-specialise
禁用这两个 channel 。并发现这种转变仍然会发生。
最佳答案
优化称为“调用模式特化”(又名 SpecConstr),它根据函数应用于哪些参数来专门化函数。优化在论文 "Call-pattern specialisation for Haskell programs" by Simon Peyton Jones 中进行了描述。 . GHC 中的当前实现与该论文中描述的内容在两个高度相关的方面有所不同:
-fno-spec-constr
生成的未经此优化的核心的相关部分, 和
-dsuppress-all -dsuppress-uniques -dno-typeable-binds
标志:
Rec {
mapMyList
= \ @ a @ b f ds ->
case ds of {
Nil -> Nil;
Cons a1 rest -> Cons (f a1) (mapMyList f rest)
}
end Rec }
Rec {
main_go
= \ x ->
Cons
(I# x)
(case x of wild {
__DEFAULT -> main_go (+# wild 1#);
5# -> Nil
})
end Rec }
main3 = \ ds -> case ds of { I# x -> I# (*# x 2#) }
main2
= $fShowMyList_$cshowsPrec
$fShowInt $fShowMyList1 (mapMyList main3 (main_go 1#))
main1 = main2 []
main = hPutStr' stdout main1 True
我认为这种优化有点令人失望,因为它只适用于同一模块内的使用。此外,很长一段时间(从
"Stream Fusion. From Lists to Streams to Nothing at All" paper from 2007 开始)人们一直希望这种优化可以优化流融合。但是,据我了解,没有人能够使其正常可靠地工作(参见
this GHC issue)。所以现在我们还是用劣质的
foldr/build
基地融合。
-dverbose-core2core
选项并检查结果。正如我所料,优化是由于 SpecConstr 优化而发生的。这是 SpecConstr 之前的核心(在 Simplifier 传递之后):
Rec {
mapMyList
= \ @ a @ b f ds ->
case ds of {
Nil -> Nil;
Cons a rest -> Cons (f a) (mapMyList f rest)
}
end Rec }
lvl = \ ds -> case ds of { I# x -> I# (*# x 2#) }
main
= case toList (mapMyList lvl (fromList (eftInt 1# 5#))) of {
...
这是 SpecConstr 之后的核心:
Rec {
$smapMyList
= \ sc ->
case sc of {
Nil -> Nil;
Cons a rest -> Cons (lvl a) (mapMyList lvl rest)
}
mapMyList
= \ @ a @ b f ds ->
case ds of {
Nil -> Nil;
Cons a rest -> Cons (f a) (mapMyList f rest)
}
end Rec }
lvl = \ ds -> case ds of { I# x -> I# (*# x 2#) }
main
= case toList (mapMyList lvl (fromList (eftInt 1# 5#))) of {
...
因此,您可以看到 SpecConstr 创建了
$smapMyList
mapMyList
的一个版本的函数专门用于
lvl
参数,即
*2
功能。
-ddump-rule-rewrites
你可以看到他们在行动:
Rule fired
Rule: SC:mapMyList0
Module: (Main)
Before: mapMyList TyArg Int TyArg Int ValArg lvl ValArg rest
After: (\ sc -> $smapMyList sc) rest
Cont: Stop[BoringCtxt] MyList Int
Rule fired
Rule: SC:mapMyList0
Module: (Main)
Before: mapMyList
TyArg Int TyArg Int ValArg lvl ValArg fromList (eftInt 1# 5#)
After: (\ sc -> $smapMyList sc) (fromList (eftInt 1# 5#))
Cont: StrictArg toList
Select nodup wild
Stop[RhsCtxt] String
这是随后的 Simplifier pass 之后的核心(它还内联了
lvl
):
Rec {
$smapMyList
= \ sc ->
case sc of {
Nil -> Nil;
Cons a rest ->
Cons (case a of { I# x -> I# (*# x 2#) }) ($smapMyList rest)
}
end Rec }
main
= case toList ($smapMyList (fromList (eftInt 1# 5#))) of {
...
这也说明了为什么这种优化也需要完全惰性的原因:
lvl
函数需要浮出,因为 SpecConstr 不适用于 lambda。这种 float 需要完全的懒惰。
关于haskell - GHC 中函数参数的内联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70060230/
简而言之:我想从可变参数模板参数中提取各种选项,但不仅通过标签而且通过那些参数的索引,这些参数是未知的 标签。我喜欢 boost 中的方法(例如 heap 或 lockfree 策略),但想让它与 S
我可以对单元格中的 excel IF 语句提供一些帮助吗? 它在做什么? 对“BaselineAmount”进行了哪些评估? =IF(BaselineAmount, (Variance/Baselin
我正在使用以下方法: public async Task Save(Foo foo,out int param) { ....... MySqlParameter prmparamID
我正在使用 CodeGear RAD Studio IDE。 为了使用命令行参数测试我的应用程序,我多次使用了“运行 -> 参数”菜单中的“参数”字段。 但是每次我给它提供一个新值时,它都无法从“下拉
我已经为信用卡类编写了一些代码,粘贴在下面。我有一个接受上述变量的构造函数,并且正在研究一些方法将这些变量格式化为字符串,以便最终输出将类似于 号码:1234 5678 9012 3456 截止日期:
MySql IN 参数 - 在存储过程中使用时,VarChar IN 参数 val 是否需要单引号? 我已经像平常一样创建了经典 ASP 代码,但我没有更新该列。 我需要引用 VarChar 参数吗?
给出了下面的开始,但似乎不知道如何完成它。本质上,如果我调用 myTest([one, Two, Three], 2); 它应该返回元素 third。必须使用for循环来找到我的解决方案。 funct
将 1113355579999 作为参数传递时,该值在函数内部变为 959050335。 调用(main.c): printf("%d\n", FindCommonDigit(111335557999
这个问题在这里已经有了答案: Is Java "pass-by-reference" or "pass-by-value"? (92 个回答) 关闭9年前。 public class StackOve
我真的很困惑,当像 1 == scanf("%lg", &entry) 交换为 scanf("%lg", &entry) == 1 没有区别。我的实验书上说的是前者,而我觉得后者是可以理解的。 1 =
我正在尝试使用调用 SetupDiGetDeviceRegistryProperty 的函数使用德尔福 7。该调用来自示例函数 SetupEnumAvailableComPorts .它看起来像这样:
我需要在现有项目上实现一些事件的显示。我无法更改数据库结构。 在我的 Controller 中,我(从 ajax 请求)传递了一个时间戳,并且我需要显示之前的 8 个事件。因此,如果时间戳是(转换后)
rails 新手。按照多态关联的教程,我遇到了这个以在create 和destroy 中设置@client。 @client = Client.find(params[:client_id] || p
通过将 VM 参数设置为 -Xmx1024m,我能够通过 Eclipse 运行 Java 程序-Xms256M。现在我想通过 Windows 中的 .bat 文件运行相同的 Java 程序 (jar)
我有一个 Delphi DLL,它在被 Delphi 应用程序调用时工作并导出声明为的方法: Procedure ProduceOutput(request,inputs:widestring; va
浏览完文档和示例后,我还没有弄清楚 schema.yaml 文件中的参数到底用在哪里。 在此处使用 AWS 代码示例:https://github.com/aws-samples/aws-proton
程序参数: procedure get_user_profile ( i_attuid in ras_user.attuid%type, i_data_group in data_g
我有一个字符串作为参数传递给我的存储过程。 dim AgentString as String = " 'test1', 'test2', 'test3' " 我想在 IN 中使用该参数声明。 AND
这个问题已经有答案了: When should I use "this" in a class? (17 个回答) 已关闭 6 年前。 我运行了一些java代码,我看到了一些我不太明白的东西。为什么下
我输入 scroll(0,10,200,10);但是当它运行时,它会传递字符串“xxpos”或“yypos”,我确实在没有撇号的情况下尝试过,但它就是行不通。 scroll = function(xp
我是一名优秀的程序员,十分优秀!