我一直在想一些新语言的概念。起初这是一个玩具,但是现在我想知道这是否真的意味着什么。我要发布此问题以堆叠溢出,以查看它是否以前已经完成,以及是否可以获取任何反馈,想法或其他信息。

我主要在阅读后开始考虑这一点 乔纳森·爱德华(Jonathan Edward)关于宣言节目的演讲. 。然后,我将其与一些旧的想法以及我在现代语言中看到的内容混合在一起。

声明性编程背后的主要思想是“什么”与“如何”。但是,我听说过很多次,所以它似乎几乎总是像“有趣”一词,它实际上并没有告诉您任何令人沮丧的东西。

在乔纳森·爱德华(Jonathan Edward)的版本中,他首先是强调 懒惰评估. 。这有一些有趣的后果,即 功能反应性编程(FRP). 。这是带有动画的FRP的示例(使用我编造的语法):

x as time * 2 // time is some value representing the current time
y as x + (2 * 500)

new Point(x, y)

因此,在这里,如果输入更改,则值将自动更改。在我最喜欢的一种语言中, d, ,“纯”和“不纯”功能之间存在区别。纯函数是与外界无关的函数,仅使用其他纯函数。否则它是不纯的。关键是您始终可以相信纯函数以返回给定参数的相同值。

我想这里适用类似的及时原理。我们的杂质是 time. 。一切都碰到了 time, , 存在 x, , 因此 y, , 因此 new Point(x, y) 不纯净。但是,请注意 (2 * 500) 是纯净的。因此,您会看到这告诉编译器其限制在哪里。我认为它就像简化了使用变量的数学表达式:

(x ^ 2) + 3x + 5
(4 ^ 2) + 3x + 5 = 16 + 3x + 5 = 21 + 3x = 3(7 + x)

通过告诉编译器什么是纯粹的,什么不是,我们可以简化我们的程序很多。另一点是渴望或可变的数据。乔纳森·爱德华(Jonathan Edward)的意见是可变和渴望的,但输出是功能性和懒惰。基本上, 给定新的输入,该程序定义了原子状态更改, , 进而 输出将只是当前状态的函数. 。如果您想看看为什么这很重要,请参阅演示文稿。输入是不纯的。懒惰评估有助于定义原子状态变化。让我们看一下如何按程序编写程序:

void main ()
{
    String input = "";

    writeln("Hello, world!");
    writeln("What's your name? ");

    input = readln();

    writeln("Hello, %s!", input);
    writeln("What's your friends name? ");

    input = readln();

    writeln("Hello to you too, %s!", input);
}

在这里 bind 关键字说如果执行以下代码,如果 begin 变化。这 mutable 关键字说输入不是懒惰,而是渴望。现在,让我们看一下“原子状态变化”如何代表它。

program:
    mutable step := 0

    bind begin:
        writeln("Hello, world!")
        writeln("What's your name? ")
        ++step

    bind readln() as input when step = 1:
        writeln("Hello, %s!", input)
        writeln("What's your friends name? ")
        ++step

    bind readln() as input when step = 2:
        writeln("Hello to you too, %s!", input)

现在,在这里,对于程序员来说,我们可以看到可以更轻松,更可读的东西。首先是丑陋 step 变量以及我们必须每次都必须递增和测试它。这是一个新版本可能是什么样子的示例:

program:
    bind begin:
        writeln("Hello, world!")
        writeln("What's your name? ")

    bind readln() as input:
        writeln("Hello, %s!", input)
        writeln("What's your friends name? ")
        yield // This just means the program jumps to here instead of at the beginning
        writeln("Hello to you too, %s!", input)
        halt

更好。不过,不完美。但是,如果我知道完美的答案,我不会在这里,对吗?

这是一个更好的例子,使用游戏引擎:

class VideoManager:
    bind begin: // Basically a static constructor, will only be called once and at the beginning
        // Some video set up stuff

    bind end: // Basically a static destructor
        // Some video shut down stuff

class Input:
    quitEvent     as handle // A handle is an empty value, but can be updated so code that's bound to it changes.
    keyboardEvent as handle(KeyboardEvent) // This handle does return a value though
    mouseEvent    as handle(MouseEvent)

    // Some other code manages actually updating the handles.

class Sprite:
    mutable x := 0
    mutable y := 0

    bind this.videoManager.updateFrame:
        // Draw this sprite

class FieldState:
    input  as new Input
    player as new Sprite

    bind input.quitEvent:
        halt

    bind input.keyboardEvent as e:
        if e.type = LEFT:
            this.player.x -= 2
        else if e.type = RIGHT:
            this.player.x += 2
        else if e.type = UP:
            this.player.y -= 2
        else if e.type = DOWN:
            this.player.y += 2

我喜欢这不需要回调,事件,甚至循环或任何东西,线程很明显。说出正在发生的事情更容易,而不仅仅是类似python的语法。我认为这是当语言开发人员意识到只有几件事人在使用标签和goto的东西时,这就是这样的事情:有条件的分支和循环。因此,他们在然后建造了如果是else,以及用于语言,标签和戈托的弃用,编译器以及人民可以分辨发生了什么。我们使用的大部分来自该过程。

回到线程,这是一个好事是线程更灵活。如果编译器可以自由地做自己想做的事情,因为我们更接近说我们想要的东西,而不是我们想要做的。因此,编译器可以利用多核和分布式处理器的优势,但仍能在没有良好线程支持的情况下补偿平台。

我想提到的最后一件事。这就是我对模板的看法。这是一个概念性的鸡蛋,我开始编程(实际上是2年前),然后开始开放。基本上,这是抽象的原则,但比阶级和物体更远。

这与我如何看待功能有关。例如:

int add (int a, int b)
{
    return a + b;
}

好的, add 返回 int, ,但是什么 曾是 它?有点像 int 等待发生。就像一个没有几块的难题。可能性有限,只有某些作品适合,但是当您完成时,您的成品可以在其他地方使用。就像我说的那样,这是抽象的原则。以下是我认为是抽象 +缺少作品的一些示例 - >具体关系:

  • 功能 +参数 - >值
  • 抽象类 +方法 - >类
  • 类 +实例值 - >对象
  • 模板 +参数 - >函数或类
  • 程序 +输入 +状态 - >输出

它们都密切相关。看来这可以利用。但是如何?同样,这就是为什么这是一个问题。但是懒惰的评估在这里很有趣,因为您可以通过一些东西 它的作品仍然缺少 还有其他东西。对于编译器而言,这主要是将名称降低到杂质的问题。就像我的示例从上面:

(x ^ 2) + 3x + 5
(4 ^ 2) + 3x + 5 = 16 + 3x + 5 = 21 + 3x = 3(7 + x)

您给编译器的零件越多,它就可以完成并将程序减少到其基本核心。和 add 上面的功能将在编译时间自动解决,因为它不依赖于外部资源。甚至可以解决许多课程和对象,以及大部分程序,具体取决于编译器的智能程度。

目前为止就这样了。如果您已经看到这些事情已经完成的示例,我想看看。而且,如果您有任何想法,创新,资源或反馈,我也很感激。

有帮助吗?

解决方案

您肯定想看看 哈斯克尔 编程语言。

Haskell是非常声明性的,懒惰的评估是内置的,甚至功能性反应性编程库也存在。但最值得注意的是,哈斯克尔是 纯粹的功能, ,即一切,实际上一切,都是 纯的.

因此,问题是Haskell如何处理通过任何IO产生的必要杂质。

答案非常适合您提出的想法。 Haskell使用一种称为的数学结构 单子 这基本上代表了产生一些值以及功能的计算 bind (>>= 作为Infix Operator),对此类计算进行序列。

因此,让我们以IO示例:阅读一行并输出您的名字...即使是纯净的,因此您不能简单地运行某些内容。相反,您建立了更大的IO计算

do
    putStr "Enter your name: "
    name <- getLine
    putStrLn ("Hello " ++ name)

看起来很当务,但是在引擎盖下,这只是语法

(putStr "Enter your name: ") >>
(getLine >>= \name ->
 putStrLn ("Hello " ++ name))

现在你可以定义这个 bind/>>= 为了 任意计算 无论如何您喜欢。因此,实际上,您谈论的所有内容都可以以这种方式实现,甚至可以通过FRP实现。

只需尝试在Stackoverflow上寻找Monads或Haskell即可;这个主题有很多问题。毕竟,它仍然是所有类型检查的所有内容,因此可以由编译器执行正确性。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top