小编Jos*_*ica的帖子

"编程代码"在编程环境中意味着什么?

我在函数式编程和PLT圈子中多次听到过"enggebras"这个术语,特别是在讨论对象,comonads,镜头等时.谷歌搜索这个术语给出了对这些结构进行数学描述的页面,这对我来说几乎是不可理解的.任何人都可以解释一下代数在编程环境中的意义,它们的意义是什么,以及它们与对象和共同体的关系?

haskell functional-programming scala category-theory recursion-schemes

334
推荐指数
4
解决办法
3万
查看次数

什么是 C++20 中的“销毁运算符删除”?

C ++ 20 引入了“销毁operator delete”:operator delete采用标记类型std::destroying_delete_t参数的新重载。

这到底是什么,什么时候有用?

c++ destructor destroy delete-operator c++20

57
推荐指数
1
解决办法
3835
查看次数

showables列表:OOP击败Haskell?

我想建立一个包含一个共同属性的不同东西的列表,即它们可以变成字符串.面向对象的方法很简单:定义接口Showable并使感兴趣的类实现它.当你不能改变类时,第二点原则上可能是一个问题,但让我们假装情况并非如此.然后你创建一个Showables 列表并用这些类的对象填充它而不会产生任何额外的噪音(例如,通常隐式地进行向上转换).这里给出了Java中的概念证明.

我的问题是我在Haskell中有什么选择?下面我讨论一些我尝试过但并不能让我满意的方法.

方法1:existensials.工作但丑陋.

{-# LANGUAGE ExistentialQuantification #-}
data Showable = forall a. Show a => Sh a

aList :: [Showable]
aList = [Sh (1 :: Int), Sh "abc"]
Run Code Online (Sandbox Code Playgroud)

我这里的主要缺点是Sh填写清单时的必要性.这非常类似于在OO语言中隐式完成的向上操作.

更一般地说,Showable已经在语言Show类型类中的虚拟包装器在我的代码中增加了额外的噪声.不好.

方法2:impredicatives.期望但不起作用.

对我来说这个列表最直接的类型和我真正想要的是:

{-# LANGUAGE ImpredicativeTypes #-}
aList :: [forall a. Show a => a]
aList = [(1 :: Int), "abc"]
Run Code Online (Sandbox Code Playgroud)

除此之外(正如我所听到的)ImpredicativeTypes"最好是脆弱而最糟糕的是"它不会编译:

Couldn't match expected type ‘a’ with actual type ‘Int’
  ‘a’ …
Run Code Online (Sandbox Code Playgroud)

haskell

40
推荐指数
6
解决办法
3140
查看次数

两个延续如何相互抵消?

我正在阅读有关列表操作的一些技巧,其中包含以下内容:

zipRev xs ys = foldr f id xs snd (ys,[])
  where
    f x k c = k (\((y:ys),r) -> c (ys,(x,y):r)) 
Run Code Online (Sandbox Code Playgroud)

我们在这里可以看到,我们有两个连续的叠放在一起。发生这种情况时,他们通常可以“取消”,如下所示:

zipRev xs ys = snd (foldr f (ys,[]) xs)
  where
    f x (y:ys,r) = (ys,(x,y):r)
Run Code Online (Sandbox Code Playgroud)

我不明白您如何“取消”堆叠的延续以从顶部的代码块到达底部的代码块。您寻找进行这种转换的方式是什么,为什么会起作用?

continuations haskell fold continuation-passing

31
推荐指数
2
解决办法
1429
查看次数

Haskell是Lisp吗?

我一直在阅读Doets和Eijck撰写的《 Haskell逻辑,数学和编程之路》(2004)。这似乎是一本受人尊敬的书,但是当我声称Haskell是Lisp家族的一员时,我感到震惊。这个准确吗?我将用S表达式,不纯函数和列表作为Lisps的特征,并将其作为唯一的复合数据结构。Haskell没有任何东西。该主张有什么理由?

lisp haskell language-comparisons

29
推荐指数
3
解决办法
6722
查看次数

为什么 struct 的析构函数是否运行取决于成员变量的类型?

我对 C++ 相当陌生,当我在构造函数和析构函数的行为中徘徊时,我发现了这个问题:

#include <iostream>

struct Student {
    std::string a;
    ~Student() {
        std::cout << "Destructor called\n";
    }
} S;

int main() {
    std::cout << "Before assigning to S\n";
    S = {""};
    std::cout << "After assigning to S\n";
}
Run Code Online (Sandbox Code Playgroud)

当我编译上面的代码g++并运行它时,它会打印:

Before assigning to S
Destructor called
After assigning to S
Destructor called
Run Code Online (Sandbox Code Playgroud)

但是当我更改std::string a;为 时const char *a;,它会打印:

Before assigning to S
After assigning to S
Destructor called
Run Code Online (Sandbox Code Playgroud)

谁能解释为什么这一变化使析构函数少运行一次?

c++

25
推荐指数
2
解决办法
1020
查看次数

Haskell 解析器是否应该允许数字文字中的 Unicode 数字?

作为练习,我正在从头开始为 Haskell 编写解析器。在制作词法分析器时,我注意到Haskell 2010 Report 中的以下规则:

digit ? ascDigit | uniDigit
ascDigit ? 0 | 1 | … | 9
uniDigit ? any Unicode decimal digit
octit ? 0 | 1 | … | 7
hexit ? digit | A | … | F | a | … | f

decimal ? digit{digit}
octal ? octit{octit}
hexadecimal ? hexit{hexit}

integer ? decimal | 0o octal | 0O octal | …

syntax haskell literals language-lawyer

15
推荐指数
1
解决办法
201
查看次数

为什么编译器坚持在这里使用被调用者保存的寄存器?

考虑这个 C 代码:

void foo(void);

long bar(long x) {
    foo();
    return x;
}
Run Code Online (Sandbox Code Playgroud)

当我在 GCC 9.3 上使用-O3或编译它时-Os,我得到这个:

bar:
        push    r12
        mov     r12, rdi
        call    foo
        mov     rax, r12
        pop     r12
        ret
Run Code Online (Sandbox Code Playgroud)

除了选择rbx而不是r12作为被调用者保存的寄存器之外,clang 的输出是相同的。

但是,我希望/期望看到看起来更像这样的程序集:

bar:
        push    rdi
        call    foo
        pop     rax
        ret
Run Code Online (Sandbox Code Playgroud)

由于无论如何您都必须将某些内容推送到堆栈中,因此将您的值推送到那里似乎更短,更简单,并且可能更快,而不是将一些任意的被调用者保存的寄存器值推送到那里,然后将您的值存储在该寄存器中。call foo当你把东西放回去后,反之亦然。

我的组装错了吗?它在某种程度上比弄乱额外的寄存器效率低吗?如果这两个的答案都是“否”,那么为什么 GCC 或 clang 不这样做呢?

Godbolt 链接


编辑:这是一个不太简单的例子,即使变量被有意义地使用,它也会发生:

long foo(long);

long bar(long x) {
    return foo(x * x) - x;
}
Run Code Online (Sandbox Code Playgroud)

我明白了:

bar:
        push    rbx …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc x86-64 register-allocation

15
推荐指数
1
解决办法
737
查看次数

为什么fread循环需要额外的Ctrl + D来用glibc发出EOF信号?

通常,为了向连接到Linux终端上的标准输入的程序指示EOF,如果我只按Enter键,则需要按Ctrl + D一次,否则按两次.但我注意到patch命令不同.有了它,如果我按下Enter键,我需要按两次Ctrl + D,否则按三次.(cat | patch相反,如果我在输入任何实际输入之前按下Ctrl + D,它就没有这种奇怪之处.)深入研究patch源代码,我追溯到它的方式循环fread.这是一个做同样事情的最小程序:

#include <stdio.h>

int main(void) {
    char buf[4096];
    size_t charsread;
    while((charsread = fread(buf, 1, sizeof(buf), stdin)) != 0) {
        printf("Read %zu bytes. EOF: %d. Error: %d.\n", charsread, feof(stdin), ferror(stdin));
    }
    printf("Read zero bytes. EOF: %d. Error: %d. Exiting.\n", feof(stdin), ferror(stdin));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在完全按原样编译和运行上述程序时,这是事件的时间表:

  1. 我的程序调用fread.
  2. fread调用read系统调用.
  3. 我输入"asdf".
  4. 我按Enter键.
  5. read系统调用返回5.
  6. freadread再次呼叫系统呼叫.
  7. 我按Ctrl + D.
  8. 该 …

c glibc libc fread eof

12
推荐指数
1
解决办法
278
查看次数

如何让 GCC 在 ah/bh/ch/dh 中放置一个字符?

假设我有一些内联汇编,需要一个特定char的值ahbhch,或dh。我怎么能告诉 GCC 把它放在那里?我没有看到相关的约束来做到这一点,但 GCC 手册说“如果你必须使用特定的寄存器,但你的机器约束没有提供足够的控制来选择你想要的特定寄存器,局部寄存器变量可能会提供一个解决方案",所以我试过:

void f(char x) {
    register char y __asm__("ah") = x;
    __asm__ __volatile__(
        "# my value ended up in %0" :: "a"(y)
    );
}
Run Code Online (Sandbox Code Playgroud)

但它没有用。它al改为:

        movb    4(%esp), %al
        # my value ended up in %al
Run Code Online (Sandbox Code Playgroud)

特定于 x86 的Q约束看起来也很接近我想要的,所以我尝试用它代替a,但结果相同。我还尝试使用更通用的r.

有趣的是,当我编译铿锵而不是GCC(是否带aQr),然后我得到了想要的结果:

        movb    4(%esp), %ah
        # my value ended up in %ah
Run Code Online (Sandbox Code Playgroud)

我还尝试使用bh、 …

c x86 assembly gcc inline-assembly

11
推荐指数
1
解决办法
161
查看次数