首页 文章

Date.now引用是否透明?

提问于
浏览
3

DateTime.NowDate.now是参考透明的吗?

这是Qiita中函数式编程文章中一个有争议的话题 .

首先,我们必须非常小心,因为“参照透明”这个词在某种意义上是一个棘手的词/概念,并且存在一个突出的讨论

What is referential transparency?

提问者说:

参考透明度这个术语是什么意思?我听说它被描述为“它意味着你可以用平等替换等于”,但这似乎是一个不充分的解释 .

一个非常典型的解释,但通常会导致我们误解的想法如下:( @Brian R. Bondy的上述页面的#2答案)

参考透明度是函数式编程中常用的术语,意味着给定函数和输入值,您将始终获得相同的输出 . 也就是说,函数中没有使用外部状态 .

我一直听到并且认为错误的典型声明是这样的:

在编程语言中, Date.now always 返回与当前时间对应的 different value ,并根据

给定一个函数和一个输入值,您将始终收到相同的输出 .

因此, Date.now 不是参考透明的!

我知道一些(功能性)程序员坚信上述声明是值得信赖的,但@Uday Reddy的#1和#3答案解释如下:

任何关于“引用透明度”的讨论,如果不理解L值,R值和填充命令式程序员概念宇宙的其他复杂对象之间的区别,从根本上是错误的 . 功能程序员的引用透明度的想法似乎与标准概念有三种不同:

  • 虽然哲学家/逻辑学家使用诸如“参考”,“外延”,“designatum”和“bedeutung”(弗雷格的德语术语)之类的术语,但功能程序员使用术语“ Value ” . (这不完全是他们的行为 . 我注意到Landin,Strachey和他们的后代也使用术语“ Value ”来谈论参考/外延 . 这可能只是Landin和Strachey介绍的术语简化,但似乎是以天真的方式使用时的巨大差异 . )

  • 功能程序员似乎相信这些“ Value ”存在于编程语言中,而不是在外部 . 在这样做时,它们与哲学家和编程语言语义学家都不同 .

  • 他们似乎相信这些“ Value ”应该通过评估获得 .

想想看,“外部状态”也是一个棘手的词/概念 .

参考透明度是函数式编程中常用的术语,意味着给定函数和输入值,您将始终获得相同的输出 . 也就是说,函数中没有使用外部状态 .

Is "current time" "external state" or "external value"?

如果我们称“当前时间”是“外部状态”,那么“鼠标事件”怎么样?

"mouse event"不是应该由编程上下文管理的状态,而是 external event .

给定一个函数和一个输入值,您将始终收到相同的输出 .

所以,我们可以理解如下:

"current time" is neither "input value" nor "external value" nor "external state" and Date.now always returns the same output corresponds to the on-going event "current time".

如果一个人仍坚持或 want to call "current time" as a "value" ,再次,

  • 功能程序员似乎相信这些"values"存在于编程语言中,而不是在外部 . 在这样做时,它们与哲学家和编程语言语义学家都不同 .

The value of "current time" never exists within the programming language, but only outside ,"current time"外的值显然通过 not programming context but the real-world's time-flow. 更新

因此,我理解Date.now是参考透明的 .

我想读你的想法 . 谢谢 .


EDIT1

What is (functional) reactive programming?

Conal Elliott @Conal还解释了功能反应式编程(FRP) .

他是最早开发FRP的人之一,并且解释如下:

  • FRP是关于 - “随时间变化表示值的数据类型”

  • 动态/演变值(即,“随时间变化的值”)本身是第一类值 .

在这个FRP的角度来看,

  • Date 可以看作是时间轴上的不可变对象的第一类值"over time" .

  • .now 是在 Date 内解决"the current time"的属性/函数

因此 Date.time 返回表示我们的"current time"的不可变和参照透明值 .


EDIT2

(在JavaScript中)

referential intransparent function

let a = 1;

let f = () => (a);

输入 Function:f 是无; Function:f 的输出取决于 a ,这取决于 f 之外的上下文

referential transparent function

let t = Date.now();

let f = (Date) => (Date.now());

虽然 Date 值存在于我们的物理世界中,但 Date 可以被视为不可变的FRP第一类值"over time" .

由于 Date 从任何编程上下文引用是相同的,我们通常隐含地可以省略 Date 作为输入值并且简单地喜欢

let f = () => (Date.now());

EDIT3

实际上,我通过电子邮件发送给了最早开发FRP的Conal Elliott @Conal . 他好心地回复并告诉我这里有类似的问题 .

How can a time function exist in functional programming?

提问者说:

所以我的问题是:函数式编程中是否存在时间函数(返回当前时间)?

  • 如果是,那么它如何存在?它是否违反了函数式编程的原理?它特别违反了引用透明性,这是函数式编程的一个属性(如果我正确理解它) .

  • 或者如果不是,那么如何才能知道函数式编程的当前时间?

而且,Conal Elliott @Conal在stackoverflow中的答案:

是的,如果将该时间作为参数给出,则纯函数可以返回时间 . 不同的时间参数,不同的时间结果 . 然后形成其他时间函数,并将它们与功能(-of-time) - 变换(高阶)函数的简单词汇表组合在一起 . 由于该方法是无状态的,因此这里的时间可以是连续的(与分辨率无关)而不是离散的,从而极大地提高了模块性 . 这种直觉是功能反应编程(FRP)的基础 .


Edit4 我对@Roman Sausarnes的答案表示赞赏 .

请允许我介绍我对函数式编程和FRP的看法 .

首先,我认为编程基本上都与数学有关,而函数式编程则追求这一方面 . 另一方面,命令式编程是描述机器操作步骤的一种方式,不一定是数学 .

像Haskel这样的纯函数式编程在处理“状态”或IO方面存在一些困难,我认为整个问题来自“时间” .

"state"或"time"对我们来说是非常主观的实体,人类 . 我们自然相信"time"正在流动或通过,"state"正在改变,即Naïve realism .

我认为Naïve对“时间”的现实主义是编程社区中所有混淆的根本危害和原因,很少讨论这方面 . 在现代物理学中,甚至从牛顿物理学中,我们以纯粹的数学方式处理时间,所以如果我们用物理学的方式来概括我们的世界,那么用纯数学函数式编程来处理世界并不困难 .

因此,我概述我们的世界/宇宙是不可变的,就像预先录制的DVD一样,只有我们的主观观点是可变的,包括“时间”或“状态” .

在编程中,不可变宇宙与我们可变的主观体验之间的唯一联系是“事件” . 纯粹的函数式编程语言,如Haskell,基本上缺乏这种观点,虽然包括Cornel Elliott在内的一些富有洞察力的研究人员继续进行FRP,但大多数人仍然认为FRP方法仍然是次要的或难以使用,并且其中许多人当然对待可变状态 .

当然,FRP是唯一的智能解决方案,特别是作为创始人的Cornel Elliott应用这一哲学观点并宣布 - first class value "over time" . 也许,不幸的是,许多程序员不会理解他真正的意思,因为他们被天真的现实主义所困,并且发现难以看待哲学或物理上不可变的实体 .

所以,如果他们讨论“ pure functional " or " referential transparency " for the advantage of mathematical integrity/consistency, to me, " Date.now " is naturally referential transparent within pure functional programming, simply because " Date.time”访问某个不可变时间线的不可变宇宙点 .


那么 referential transparency 在@Reddy或@Roman Sausarnes disususses这样的Denotational语义中呢?

我概述了FP中的引用透明性,特别是在Haskell社区中,所有这些都与数学完整性/一致性有关 .

当然,也许我可以遵循Haskell社区对“引用透明度”的更新定义,实际上,如果我们判断代码是不透明的,那么我们判断代码在数学上是不一致的,对吗?

实际上,再一次,

How can a time function exist in functional programming?

程序员质疑如下:

所以我的问题是:函数式编程中是否存在时间函数(返回当前时间)?

  • 如果是,那么它如何存在?它是否违反了函数式编程的原理?它特别违反了参考透明度,这是功能性的特性之一编程(如果我正确理解它) .

  • 或者如果不是,那么如何才能知道函数式编程的当前时间?


Consensus

违反了函数式编程的原理

=违反参照透明度,这是函数式编程的属性之一

=数学上不一致!!


这是我们常见的看法,对吗?

在这个问题中,许多人回答说“返回当前时间的函数”并不是参考透明,特别是在Haskell社区对“参照透明度”的定义中,许多人提到它是关于数学一致性的 .

然而,只有少数人回答“返回当前时间的功能”是参考透明的,其中一个答案来自FRP的角度来自Conal Elliott @Conal .

IMO,FRP,将时间流作为一流的不可变值“随着时间的推移”处理的观点是一种正确的方式,正如我上面提到的物理学一样的数学原理 .

那么“Date.now”/“函数返回当前时间”如何成为Haskell上下文的引用不透明?

好吧,我能想到的唯一解释是Haskell社区对“参照透明度”的更新定义有些不对 .

Event-driven & Mathematical integrity/consistency

我提到过 - 在编程中,不可变的宇宙和我们可变的主观体验之间的唯一联系是“事件”或“事件驱动” .

功能编程以事件驱动的方式进行评估,另一方面,命令式编程通过代码中描述的机器操作的步骤/例程来评估 .

“Date.now”取决于“事件”,并且原则上,“事件”对于代码的上下文是未知的 .

那么,事件驱动会破坏数学完整性/一致性吗?绝对不 .

Mapping Syntax to Meaning - indexical(index finger)

C.S. Peirce introduced the term ‘indexical’ to suggest the idea of pointing (as in ‘index finger’) . ⟦I⟧,[[here]],[[now]]等 .

可能这在数学上与Haskell中的“Monad”,“functor”事物相同 . 在即使在Haskell中的指称语义中,[[now]]作为“食指”也是清楚的 .

Indexical(index finger) is subjective and so is Event-driven

[[I]],[[here]],[[now]]等等是主观的,再次,在编程中,不可变的客观宇宙与我们可变的主观体验之间的唯一联系是“事件”或“事件”驱动的”

因此,只要[[now]]绑定到“事件驱动”编程的事件声明,我认为主观(依赖于上下文)的数学不一致就不会发生 .


Edit5

@Bergi给了我一个很好的评论:

是的,Date.now,外部值,是引用透明的 . 它总是意味着“当前时间” . 但是Date.now()不是,它是一个函数调用,根据外部状态返回不同的数字 . 引用透明的“当前时间概念”的问题在于我们无法用它来计算任何东西 . @KenOKABE:似乎与Date.now()的情况相同 . 问题在于它并不意味着当前的时间,而是在不同的时间 - 程序需要时间来执行,这就是它不纯的原因 . 当然,我们可以设计一个引用透明的Date.now函数/ getter,它总是返回程序启动的时间(好像程序执行是立即的),但这不是Date.now()/ Date.Now的工作方式 . 它们取决于程序的执行状态 . - Bergi

我想我们需要讨论它 .

Date.now ,外部值,是参考透明的 .

[[Date.now]] is as I mention in #Edit4, an indexical(index finger) that is subjective, but as long as it remains in indexical domain (without an execution/evaluation), it is referentially transparent ,我们同意了 .

However, @Bergi suggests Date.now() (with an execution/evaluation) returns "different values" at different times, and which is no longer referentially transparent. 我们还没有达成一致意见 .

我认为他已经证明了这个问题,但只存在于命令式编程中:

console.log(Date.now()); //some numeric for 2016/05/18 xx:xx:xx ....
console.log(Date.now()); //different numeric for 2016/05/18 xx:xx:xx ....

在这种情况下,我同意 Date.now() 不是引用透明的 .

但是,在功能编程/声明性编程范例中,我们永远不会像上面那样编写 . 我们必须这样写:

const f = () => (Date.now());

而且,这 f is evaluated in some "event-driven" context . 这就是功能编程代码的行为方式 .

是的, this code is identical to

const f = Date.now;

因此,在函数式编程/声明性编程范例中, Date.nowDate.now() (带执行/评估)在不同时间返回"different values"永远不会有问题 .

所以,正如我在 EDIT4 中提到的那样,只要[[now]]绑定到"Event-driven" Programming的事件声明,我认为主观(依赖于上下文)的数学不一致就不会发生 .

1 回答

  • 4

    好吧,我'm going to take a stab at this. I'我不是这方面的专家,但我花了一些时间考虑你所链接的@UdayReddy's answers to this question,我想我已经把头包裹起来了 .

    分析哲学中的参照透明度

    我想你必须从雷迪先生的回答开始另一个问题 . 雷迪先生写道:

    在指导哲学中使用术语“指示物”来谈论表达所指的事物 . 它与编程语言语义中的“含义”或“外延”大致相同 .

    注意使用"denotation"这个词 . 编程语言具有语法或语法,但它们也具有语义或含义 . Denotational semantics是将语言的语法翻译成其数学意义的实践 .

    据我所知,指称语义并没有被广泛理解,尽管它是理解,设计和推理计算机程序的最有力的工具之一 . 我必须花一点时间来为你的问题的答案奠定基础 .

    Denotational Semantics:将语法映射到含义

    指称语义背后的思想是计算机语言中的每个句法元素都具有相应的数学意义或语义 . 指称语义是语法和语义之间的显式映射 . 取句法数字 1 . 您可以将其映射到其数学意义,这只是数学数字 1 . 语义功能可能如下所示:

    syntax
       ↓
      ⟦1⟧ ∷ One
            ↑ 
        semantics
    

    有时双方括号用于表示"meaning",在这种情况下,语义侧的数字 1 拼写为 One . 这些只是用于指示何时讨论语义以及何时讨论语法的工具 . 你可以阅读那个函数来表示“句法符号 1 的含义是数字 One ” .

    我上面使用的例子看起来微不足道 . 当然 1 表示 One . 还有什么意思?但是,它没有必要 . 你可以这样做:

    ⟦1⟧ ∷ Four
    

    那将是愚蠢的,没有人会使用这种愚蠢的语言,但它将是一种有效的语言 . 但关键是指称语义允许我们明确我们编写的程序的数学意义 . 以下是使用lambda表示法对整数 x 求平方的函数的表示:

    ⟦square x⟧ ∷ λx → x²
    

    现在我们可以继续讨论参考透明度 .

    参考透明度是关于意义

    请允许我再次依靠Uday先生的答案 . 他写:

    如果在该上下文中用引用同一实体的另一个术语替换术语而不改变含义,则句子中的上下文是“引用透明的” .

    将此与您向普通程序员询问参考透明度意味着什么的答案相比较 . 他们通常会说出你上面引用的答案:

    参考透明度是函数式编程中常用的术语,意味着给定函数和输入值,您将始终获得相同的输出 . 也就是说,函数中没有使用外部状态 .

    这个答案在 Value 和副作用方面定义了参考透明度,但它完全忽略了意义 .

    这是一个在第二个定义下不是引用透明的函数:

    var x = 0
    
    func changeX() -> Int {
        x += 1
        return x
    }
    

    它读取一些外部状态,改变它,然后返回值 . 它不需要输入,每次调用它时都会返回不同的值,并且它依赖于外部状态 . 咩 . 很重要 .

    给定正确的指称语义,它仍然是引用透明的 .

    为什么?因为您可以将其替换为具有相同语义含义的另一个表达式 .

    现在,该函数的语义更加令人困惑 . 我不知道如何定义它 . 它与状态转换有关,给定状态 s 和产生新状态 s' 的函数,表示可能看起来像这样,但我不知道这是否在数学上是正确的:

    ⟦changeX⟧ ∷ λs → (s → s')
    

    是对的吗?我还没有理解它 . 然而,通过 Build 外延语义,他确定命令式语言与函数式语言一样具有引用透明性 . 为什么?因为可以精确地描述数学意义 . 一旦你知道了某些东西的精确数学意义,你就可以用任何其他具有相同含义的术语代替它 . 所以,即使我不知道 changeX 函数的真正语义是什么,我知道如果我有另一个具有相同语义含义的术语,我可以换掉另一个术语 .

    那么Date.now怎么样?

    虽然我,我甚至不确定它是什么语言怀疑它可能是Javascript . 但谁在乎 . 它的指称语义是什么?这是什么意思?在不改变程序含义的情况下,您可以插入什么内容?

    丑陋的事实是,我们大多数人都没有线索!表达语义不是让你向我解释的 . 采取任何由大约20行非平凡代码组成的命令式程序,并告诉我它的数学含义是什么 . 我挑战你 .

    相比之下,Haskell的指称语义非常简单 . 我对Haskell知之甚少 . 除了在ghci中乱搞之外,我从来没有做过任何编码,但是它的强大之处在于语法比我所知道的任何其他语言更紧密地跟踪语义 . 作为一种纯粹的,严格的函数式语言,语义就在语法的表面上 . 语法由定义含义的数学概念定义 .

    事实上,语法和语义是如此紧密相关,功能程序员已经开始将两者混为一谈 . (我谦卑地提交这个意见并等待反对 . )这就是为什么你从FPers那里得到关于 Value 而不是意义的参照透明度的定义 . 在像Haskell这样的语言中,这两者几乎无法区分 . 由于没有可变状态,并且每个函数都是纯函数,所以您只需要查看函数计算时产生的值,并且基本确定其含义 .

    也许新时代的FPer对参考透明度的解释在某种程度上比我在上面总结的更有用 . 这是不容忽视的 . 毕竟,如果我上面写的是正确的,那么具有指称语义的所有内容都是引用透明的 . 没有非引用透明函数,因为每个函数都具有数学意义(虽然它可能是模糊的,很难定义),并且您总是可以用具有相同含义的另一个术语替换它 . 这有什么用?

    好吧,我们知道,我们不知道 Date.now 的指称语义是什么,或者它在数学意义上意味着什么 . 它的引用是否透明?是的,我确信它是,因为它可以被具有相同语义的另一个函数替换 . 但我不知道如何评估该函数的语义,因此它的引用透明性对我作为程序员没用 .

    因此,如果我从所有这些中学到了一件事,那就是更少关注某些东西是否符合某种“参照透明度”的定义,而更多的是关于尝试用小的,数学上可组合的程序来制作程序具有精确语义含义的部分,即使我能理解 .

相关问题