【问题标题】:How to evaluate an Haskell expression immediately?如何立即评估 Haskell 表达式?
【发布时间】:2013-10-16 12:51:02
【问题描述】:

当我使用 JS 时,我有两个选项来处理一个函数。

var a = function() {};
var b = a;     // b is the function a itself.
var c = a();   // c is result of the evaluation of function a.

AFAIK,Haskell 默认是懒惰的,所以我总是默认得到b。但是如果我想得到c,我该怎么办?

更新

我想我应该明确地写一个词

我在ghci 中做了类似的事情。

let a = getLine
a

我想让getLine 的结果变成a

更新2

我记下这段代码,以供像我这样的人以后参考。 在@Ankur 的帮助下,我可以更正对 Haskell 的翻译。 上面的代码示例不是一个好的示例,因为函数 a 不返回任何内容。 如果我这样改变它;

var a = function(x,y) { return x * y; };
var b = a;     // b is the function a itself.
var c = a();   // c is result of the evaluation of function a.

翻译成Haskell会变成这样。

let a = \ x y -> x* y    // Anonymous lambda function.
let b = a
let c = a 100 200        

【问题讨论】:

  • 您可能想要一个字符串,但getline 的类型为IO String。 IO 是一种特殊的盒子,你可以把东西放进去,但永远无法取回。你需要阅读 Haskell monadic I/O system。
  • @n.m. you can put stuff inside but cannot get it back, ever 这是不正确的。应该是:您必须在框的上下文中工作才能使用框内的值。
  • @Ankur 你是这样说的,是的。有点我不打算提供 monad 教程。
  • 感谢您的讨论,但无论如何,像这样的基本示例对像我这样的初学者更有价值和有帮助。我只是希望我最终能理解 Monad 是什么。
  • 请注意,由于在 Haskell 中所有函数都在 curried form 中,因此 JavaScript 函数 function(x,y) { return x*y; } 将转换为 \(x,y) -> x * y。 Haskell 函数 \x y -> x * y 将是 function(x) { return function(y) { return x*y; } }

标签: haskell evaluation strict


【解决方案1】:

您的 JS 代码将转换为 Haskell:

Prelude> let a = (\() -> ())
Prelude> let b = a
Prelude> let c = a()

您的 JS 函数没有任何内容(您可以将其建模为 () 类型)并且什么也不返回,即再次 ()

getLineIO String 类型的值,所以如果你说let a = getLinea 将成为IO String 类型的值。你想要的是从这个IO String中提取String,可以这样做:

a <- getLine

【讨论】:

  • 我从来不知道Haskell函数也可以用()操作符调用。
  • @Eonil: () 是 Haskell 中的一种类型,它只有一个值,也称为 ()。由于它是一个值,因此您可以将其传递给接受 () 类型值的函数。如果你然后删除函数名和参数之间的一些空格,你会得到奇怪的外观,例如id()id ()()
  • 别搞糊涂了,() 不是一个操作符,而是一个类型(在类型签名中)和上面使用的一个值。所以a () 是函数a 应用于值()
【解决方案2】:

请注意,与 Javascript 的平行并不完全正确——例如,假设 a 返回一个数字,b + b 在 Haskell 中有意义,但在您的示例 Javascript 中则没有意义。原则上,Haskell 中的函数是只有一个参数的函数——看起来是两个参数的函数是一个参数的函数,它返回一个参数的函数,该函数返回一个值。 Haskell 中的b 不是未评估的“零参数函数”,而是未评估的值。

要引入严格性,您可以使用seq,它接受两个参数,第一个被严格评估,第二个被返回。 Read more.

这是该页面中的一个示例,其中seq 用于强制立即评估z'

foldl' :: (a -> b -> a) -> a -> [b] -> a
foldl' _ z [] = z
foldl' f z (x:xs) = let z' = f z x in z' `seq` foldl' f z' xs

注意z' 稍后再次用作foldl' 的第二个参数的方式,因为seq 只是丢弃了它的第一个参数的值。

【讨论】:

    【解决方案3】:
    1. Haskell 是 non-strict,并不懒惰。
    2. 许多表达式将被严格评估,请参阅here,因此您通常可以简单地通过代码结构强制执行严格性。
    3. 在 Haskell 中,如果 c 的类型与 a() 的返回类型(值)匹配,那么这就是分配给它的类型(而不是函数本身)。
    4. Haskell 可能会推迟计算,直到您的代码真正需要 c 的值,但在大多数情况下您不必关心。

    为什么要提前强制评估?通常,在 Haskell 中这样做的唯一原因是性能。在不太纯的语言中,您可能依赖于副作用,但在 Haskell 中不会出现这种情况 - 除非您正在使用 IO monad,并且它为您提供了强制顺序评估所需的一切。

    更新啊,所以你正在使用IO

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-27
      • 1970-01-01
      相关资源
      最近更新 更多