小编gla*_*erl的帖子

GHC可以实现哪些优化可靠?

GHC有很多可以执行的优化,但我不知道它们是什么,也不知道它们在多大程度上被执行的可能性.

我的问题是:我可以期望每次或几乎可以应用哪些转换?如果我查看将要经常执行(评估)的一段代码,我的第一个想法是"嗯,也许我应该优化它",在这种情况下,我的第二个想法是,"甚至不要考虑它, GHC得到了这个"?

我正在阅读文章Stream Fusion:从列表到流到没有任何东西,以及他们用于将列表处理重写为不同形式的技术,GHC的正常优化将可靠地优化为简单的循环对我来说是新颖的.如何判断自己的程序何时符合这种优化条件?

GHC手册中有一些信息,但它只是回答问题的一部分.

编辑:我正在开始赏金.我想要的是一个低级转换列表,如lambda/let/case-floating,类型/构造函数/函数参数特化,严格性分析和拆箱,worker/wrapper,以及我遗漏的任何其他重要的GHC做的事情,以及输入和输出代码的解释和示例,以及理想情况下总效应大于其各部分之和的情况.理想情况下,有些人提到何时不会发生转变.我不期待对每个转换的新颖长度的解释,一些句子和内联单行代码示例就足够了(或者链接,如果它不是20页的科学论文),只要大图是在它结束时清楚.我希望能够查看一段代码,并能够很好地猜测它是否会编译成紧密循环,或者为什么不编译,或者我需要改变它来制作它.(我对像流融合这样的大优化框架(我只是阅读了一篇关于它的论文)感兴趣;更多的是那些编写这些框架的人所拥有的知识.)

optimization haskell ghc

177
推荐指数
3
解决办法
8824
查看次数

是否有任何理由不使用INLINABLE pragma作为函数?

文件规定:

函数f上的{ - #INLINABLE f# - } pragma具有以下行为:

  • 虽然INLINE说"请内联我",INLINABLE说"请随意内联我;请自行决定".换句话说,选择留给GHC,它使用与无编译指示函数相同的规则.与INLINE不同,该决定是在呼叫站点进行的,因此会受到内联阈值,优化级别等因素的影响.

  • 与INLINE类似,INLINABLE pragma保留原始RHS的副本以用于内联,并且无论RHS的大小如何,都将其保留在接口文件中.

  • 使用INLINABLE的一种方法是结合内联特殊函数(第7.18节"特殊内置函数").调用内联f非常难以内联f.为了确保f可以内联,最好将f的定义标记为INLINABLE,以便GHC保证在不管它有多大的情况下展开展开.此外,通过将f注释为INLINABLE,可以确保f的原始RHS内联,而不是f GHC优化器产生的任何随机优化版本.

  • INLINABLE pragma也适用于SPECIALIZE:如果将函数f标记为INLINABLE,那么随后可以在另一个模块中进行SPECIALIZE(参见第7.16.8节"SPECIALIZE pragma").

  • 与INLINE不同,可以在递归函数上使用INLINABLE编译指示.主要原因是允许以后使用SPECIALIZE

它的缺点是什么?

它是否使界面文件更大,更大?它是否使编译速度慢得多?

有没有理由我不应该在我写的每个导出函数上放置一个INLINABLE pragma?是否有任何理由GHC没有在我写的每个导出函数上放置一个INLINABLE pragma?

haskell inline pragma ghc

44
推荐指数
1
解决办法
1971
查看次数

C++:指向虚拟成员函数的单态版本的指针?

在C++中,可以获得指向类的(非静态)成员函数的指针,然后在对象上调用它.如果函数是虚函数,则根据对象的动态类型动态调度调用.通过显式提供包含要使用的版本的范围,也可以(不使用成员指针)以单态方式调用对象的虚拟成员函数.以下代码演示了这一点:

#include <iostream>
using std::cout; using std::endl;

struct Foo
{
    virtual void foo() { cout << 1 << endl; }
};

struct Foo2: public Foo
{
    virtual void foo() { cout << 2 << endl; }
};

int main( int, char** )
{
    Foo *foo = new Foo2;

    void (Foo::*foo_pointer)() = &Foo::foo;

    foo->foo();            // prints 2
    foo->Foo::foo();       // prints 1
    (foo->*foo_pointer)(); // prints 2
}
Run Code Online (Sandbox Code Playgroud)

我想要做的是将两者结合起来,并获得指向成员函数的单态版本的指针; 即,我想要一个指向Foo :: foo的指针,它总是调用foo的基类版本,并打印1,即使它是在Foo2上调用的.但是,我还没有找到办法做到这一点.可能吗?

(除了编写一个新的非虚函数的繁琐的手动方式,它进行单态调用,然后获得指向它的指针.)

c++ virtual-functions member-function-pointers

27
推荐指数
1
解决办法
1551
查看次数

OverlappingInstances有什么坏处?

透过一些最近的问题,我想我会把焦点放在旧的柏忌上OverlappingInstances.

几年前,我可能一直在认真地问这个问题:毕竟,你可以提供有用的默认实例,而其他人可以在需要时用更具体​​的实例覆盖它们,那可能是多么糟糕?

一路走来,我对那些OverlappingInstances真的不那么干净,最好避免的观点表示赞赏; 主要源于它在理论上不是很有根据,不像其他大的扩展.

但是考虑一下,如果有人问我,我不确定我是否可以向另一个人解释它真的如此糟糕.

我正在寻找的是使用OverlappingInstances可能导致不良事件发生的方式的具体示例,无论是通过颠覆类型系统还是其他不变量,或者只是一般意外或混乱.

我所知道的一个特殊问题是,它破坏了仅添加或删除单个模块导入不能改变程序含义的属性,因为扩展打开后,可以静默添加或删除新的实例重叠.虽然我可以看到为什么这是令人不快的,但我不明白为什么它是惊天动地的.

奖金问题:只要我们谈论有用但不理论上有充分根据的扩展可能导致不良事件,为什么GeneralizedNewtypeDeriving不能得到同样糟糕的说唱?是因为负面可能性更容易本地化; 更容易看出会导致问题的原因并说"不要那样做"?

(注意:如果答案主要集中在哪个方面OverlappingInstances,我更愿意,而不是IncoherentInstances需要更少的解释.)

编辑:有还不错的答案类似的问题在这里.

haskell

17
推荐指数
1
解决办法
751
查看次数

专门针对最小参数数量的可变参数模板模板参数:合法与否?

我有代码:

#include <cstdio>

template<template<typename...> class>
struct Foo 
{ 
    enum { n = 77 };
};

template<template<typename, typename...> class C>
struct Foo<C>
{
    enum { n = 99 }; 
};

template<typename...> struct A { };

template<typename, typename...> struct B { };

int main(int, char**)
{
    printf("%d\n", Foo<A>::n);
    printf("%d\n", Foo<B>::n);
}
Run Code Online (Sandbox Code Playgroud)

这个想法是它template<typename, typename...> class的一个子集template<typename...> class,因此有可能专注于它.但它非常深奥,所以也许不是.我们来试试吧.

GCC 4.7说:

$ g++ -std=c++11 test157.cpp 
Run Code Online (Sandbox Code Playgroud)

它汇编了!

运行它:

$ ./a.out 
77
99
Run Code Online (Sandbox Code Playgroud)

有用!

Clang 3.1说:

$ clang++ -std=c++11 test157.cpp
test157.cpp:10:8: error: class template …
Run Code Online (Sandbox Code Playgroud)

c++ templates template-specialization variadic-templates c++11

16
推荐指数
1
解决办法
2133
查看次数

C++ 11:抽象const,volatile,左值引用和rvalue引用限定成员函数指针?

C++ 03可以让你有资格函数的参数为const,volatile和/或左值引用(&).

C++ 11增加了一个:rvalue references(&&).

此外,C++允许您根据参数的限定符重载函数,以便在调用函数时选择最合适的重载.

成员函数在概念上可以被认为是一个函数,它接受一个额外的参数,其类型是对它所属的类的实例的引用.可以基于此"额外参数"的限定符来重载成员函数,其方式与任何其他参数非常相似.这通过将限定符放在函数签名的末尾来表示:

struct Foo
{
    int& data();             // return a non-const reference if `this` is non-const
    const int& data() const; // return a const reference if `this` is const
};
Run Code Online (Sandbox Code Playgroud)

在C++ 03,constvolatile预选赛是可能的,C++ 11还允许&&&(&理论上可以被允许在C++ 03,但它不是).

可以使用限定符的任何组合,除了&并且&&是互斥的,这使得C++ 03中的2 ^ 2 = 4种可能性和C++ 11中的2 ^ 4-4 = 12.

当你想使用成员函数指针时,这可能会非常痛苦,因为它们在这些限定符中甚至不是多态的:this作为参数传递的成员函数指针的" 类型" 的限定符必须与那些完全匹配关于它被传递的参数的类型.C++也没有提供用于抽象限定符的明确工具.在C++ 03中,这基本上没问题,因为你必须编写一个const版本和一个非 …

c++ overloading member-function-pointers qualifiers c++11

13
推荐指数
1
解决办法
1414
查看次数

StableNames比reallyUnsafePtrEquality#有什么优势,反之亦然?

数据稳定名称 a

稳定名称具有以下属性:如果sn1 :: StableName和sn2 :: StableName和sn1 == sn2,则通过在同一对象上调用makeStableName创建sn1和sn2.

反过来不一定如此:如果两个稳定名称不相等,那么它们命名的对象可能仍然相等.

reallyUnsafePtrEquality# :: a - > a - > Int#

reallyUnsafePtrEquality#返回GHC堆上的两个对象是否是同一个对象.它真的不安全,因为垃圾收集器会移动东西,闭包等.据我所知,它可以返回假阴性(它说两个对象不一样,但它们都是),但不是误报(说它们当他们不是时,他们会一样.

他们两个似乎做了同样的基本事情:他们可以告诉你两个对象是否绝对相同,但不是它们是否绝对不是.

我能看到的StableNames的优点是:

  • 他们可以散列.
  • 他们不那么不便携.
  • 他们的行为得到了很好的定义和支持.
  • 他们没有真正的不安全作为他们名字的一部分.

我可以在reallyUnsafePtrEquality#中看到的优点:

  • 它可以直接在有问题的对象上调用,而不必创建单独的StablesNames.
  • 您不必通过IO函数来创建StableNames.
  • 您不必保留StableNames,因此内存使用率较低.
  • RTS不需要做任何使StableNames工作的魔法,因此性能可能更好.
  • 它的名字真的很不安全,最后是#.铁杆!

我的问题是:

  • 我错过了什么吗?

  • 是否有任何用例,StableNames与他们命名的对象分开是有利的?

  • 是否比另一个更准确(不太可能返回假阴性)?

  • 如果你不需要散列,不关心可移植性,并且不会被使用名为reallyUnsafe的东西所困扰,是否有理由更喜欢StableNames而不是reallyUnsafePtrEquality#?

haskell ghc

13
推荐指数
1
解决办法
996
查看次数

删除所有构造函数(或其他函数)的最佳样式?

假设我想制作一个无法构造的类型(不要问为什么).

struct Impossible
{
Run Code Online (Sandbox Code Playgroud)

我可以这样做:

    Impossible() = delete;
    // disable automatically generated constructors, don't declare any others
    Impossible(const Impossible&) = delete;
    // I suppose this is redundant with nothing to copy
Run Code Online (Sandbox Code Playgroud)

或者像这样:

    Impossible(...) = delete;
    // explicitly disable all constructors
Run Code Online (Sandbox Code Playgroud)

或者像这样:

    template<typename... Ts>
    Impossible(Ts...) = delete;
    // explicitly disable all constructors, template version
};
Run Code Online (Sandbox Code Playgroud)

我想我可以对任何函数提出同样的问题,而不仅仅是构造函数.

我选择哪一个有什么不同?在语法方面,我认为我喜欢第二种选择.但是,在任何情况下,是否有可能检测到差异(除了错误信息的文本中)?

c++ memory-management delete-operator c++11

9
推荐指数
3
解决办法
2062
查看次数

抽象非类型模板参数的类型

我想编写一个模板,可以将类型解析为具有非类型模板参数的模板及其非类型模板参数.例如,它将解构Array<5>template<int> Array5,但一般会用于任何类型的非类型模板参数(整数类型,指针,成员指针等).

首先尝试,使用模板专业化:

template<typename T> struct foo { enum { n = 1 }; };

template<int x> struct bar { enum { n = x }; };

template<typename T, template<T> class X, T x>
struct foo< X<x> > { enum { n = x }; }; // here x must be of integral type, but that's just for testing

int main(int, char**) { return foo< bar<16> >::n; }
Run Code Online (Sandbox Code Playgroud)

Clang 3.1说:

test145.cpp:6:8: warning: class template …
Run Code Online (Sandbox Code Playgroud)

c++ templates

6
推荐指数
1
解决办法
848
查看次数

是否可以直接将函数指针作为块参数传递?

假设我有一个需要块的函数:

void foo(Foo (^block)(Bar));
Run Code Online (Sandbox Code Playgroud)

并说我有一个具有相同签名的函数,除了不是块:

Foo myFunction(Bar);
Run Code Online (Sandbox Code Playgroud)

我可以做这个:

foo(^(Bar bar) { return myFunction(bar); });
Run Code Online (Sandbox Code Playgroud)

但我宁愿这样做,如果有效,这将是相同的:

foo(&myFunction);
Run Code Online (Sandbox Code Playgroud)

如果我尝试,XCode说:

No matching function for call to 'foo'
Run Code Online (Sandbox Code Playgroud)

块是一个函数指针和一些上下文,因此在该级别上,想要使用普通函数指针作为具有空上下文的块似乎是合理的.可能吗?

objective-c objective-c-blocks

6
推荐指数
1
解决办法
2397
查看次数

有没有办法在运行时确定GHC中的抽象值是否为函数?

我想知道是否有可能有一个功能(有点类似dataToTag#):

isFunction# :: a -> Bool
Run Code Online (Sandbox Code Playgroud)

或者可能等同于:

isFunction# :: Any -> Bool
Run Code Online (Sandbox Code Playgroud)

它返回TrueIFF传递作为参数是一种类型的值a -> b(或者,对于这个问题,a => b在运行时)对某些类型的ab,或newtype它的基本类型是(所以它"通过看见" newtypeS,但当然不是data),没有强迫它的论点.我在GHC.Prim自己没有看到这样的东西,但我可能已经错过了一些东西,或者可能用手动的CMM primop或其他东西.

既然问题已经发生在我身上,我对答案本身就很好奇(问题Y),但我想到的最初的原因(问题X)是,通常针对的seq是,它通过以下方式打破eta等值:从而可以观察之间的差异undefined\_ -> undefined,我想知道是否有可能使一个版本的seq(myseq a = if isFunction# a then flip const a else seq a),这仍然是"神奇的多态性"(工作forall a),而只是独自离开的功能.

haskell ghc

6
推荐指数
1
解决办法
99
查看次数