标签: strictness

Haskell:什么是弱头正常形式?

什么是弱头范式(WHNF)是什么意思?什么是头标准型(HNF)和范式(NF)是什么意思?

真实世界Haskell说:

熟悉的seq函数将表达式计算为我们称之为head normal form(缩写为HNF)的表达式.它一旦到达最外面的构造函数("头部")就会停止.这与正常形式(NF)不同,其中表达式被完全评估.

您还将听到Haskell程序员引用弱头正常形式(WHNF).对于正常数据,弱头正常形式与头部正常形式相同.差异只出现在功能上,而且我们在这里无关紧要.

我已经阅读了一些资源和定义(Haskell WikiHaskell邮件列表自由词典),但我没有得到它.有人可能举一个例子或提供外行定义吗?

我猜它会类似于:

WHNF = thunk : thunk

HNF = 0 : thunk 

NF = 0 : 1 : 2 : 3 : []
Run Code Online (Sandbox Code Playgroud)

如何做seq($!)与WHNF和HNF有关?

更新

我还是很困惑.我知道有些答案会忽略HNF.通过阅读各种定义,似乎WHNF和HNF中的常规数据之间没有区别.但是,它似乎与功能有所区别.如果没有差异,为什么还seq需要foldl'

另一个混淆点来自Haskell Wiki,它指出seq减少到WHNF,并且对以下示例不做任何处理.然后他们说他们必须seq用来强迫评估.那不是强迫它到HNF吗?

常见的新手堆栈溢出代码:

myAverage = uncurry (/) . foldl' (\(acc, len) x -> (acc+x, len+1)) (0,0)
Run Code Online (Sandbox Code Playgroud)

了解seq和弱头正常形式(whnf)的人可以立即明白这里出了什么问题.(acc + x,len + 1)已经在whnf中,所以seq将值减少到whnf,对此无效.这段代码将像原始的foldl示例一样构建thunks,它们只是在元组内部.解决方案只是强制元组的组件,例如

myAverage …
Run Code Online (Sandbox Code Playgroud)

haskell definition strictness weak-head-normal-form

279
推荐指数
6
解决办法
3万
查看次数

什么是Haskell的严格要点?

我们都知道(或应该知道)Haskell默认是懒惰的.在必须对其进行评估之前,不评估任何内容.那么什么时候必须评估一下?Haskell必须严格要点.我把这些称为"严格点",虽然这个术语并不像我想象的那么广泛.据我说:

Haskell中的减少(或评估)发生在严格点处.

所以,问题是:什么,准确地说,是Haskell的严格点?我的直觉说main,seq/爆炸模式,模式匹配以及IO通过执行的任何动作main都是主要的严格点,但我不知道为什么我知道这一点.

(另外,如果他们不叫"严点",什么他们叫什么名字?)

我想一个好的答案将包括一些关于WHNF等的讨论.我也想象它可能触及lambda演算.


编辑:关于这个问题的其他想法.

正如我在这个问题上的反思,我认为在严格点的定义中添加一些东西会更清楚.严格点可以具有不同的上下文和不同的深度(或严格性).回到我的定义"Haskell的减少只发生在严格点",让我们在这个定义中添加这个子句:"只有在评估或减少周围环境时才会触发严格点."

所以,让我试着让你开始我想要的那种答案.main是严格的一点.它被特别指定为其上下文的主要严格点:程序.当main评估程序(的上下文)时,激活main的严格点.主要深度是最大的:必须进行全面评估.Main通常由IO动作组成,它们也是严格点,其背景是main.

现在你尝试:seq用这些术语讨论和模式匹配.解释功能应用的细微差别:它是如何严格的?怎么回事?怎么样deepseqletcase陈述?unsafePerformIODebug.Trace?顶级定义?严格的数据类型?邦模式?等等.这些项目中有多少只能用seq或模式匹配来描述?

haskell language-design lazy-evaluation strictness

88
推荐指数
5
解决办法
5437
查看次数

数据类型中严格字段的​​优点

这可能现在有点模糊,但我一直在想这一段时间.据我所知!,可以确保在构造值之前评估数据构造函数的参数:

data Foo = Bar !Int !Float
Run Code Online (Sandbox Code Playgroud)

我经常认为懒惰是一件好事.现在,当我浏览消息来源时,我会看到比非!变体更严格的字段.

这有什么好处,为什么我不应该把它保持懒惰呢?

haskell strictness

30
推荐指数
2
解决办法
3262
查看次数

unboxed类型和严格性之间的关系是什么?

未装箱的类型,比如Int#,和严格的功能,f (!x) = ...是不同的,但我看到概念上的相似性 - 他们在某种程度上不允许暴力/懒惰.如果Haskell是像Ocaml这样的严格语言,那么每个函数都是严格的,并且每个类型都是未装箱的.unboxed类型与强制执行之间的关系是什么?

evaluation haskell lazy-evaluation strictness

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

什么是脊柱严格

在Haskell中,经常提到与懒惰评估相关的术语脊柱严格性.虽然我对这意味着有一个模糊的理解,但对于以下方面有一个更具体的解释会更好:

  • 什么是脊柱的数据结构
  • 什么是脊柱严格呢?
  • 将spine严格数据结构与惰性数据结构进行比较有什么好处

haskell lazy-evaluation data-structures strictness

25
推荐指数
1
解决办法
1482
查看次数

分析Haskell程序

我有一段代码,使用的概率分布重复采样sequence.在道德上,它做了这样的事情:

sampleMean :: MonadRandom m => Int -> m Float -> m Float
sampleMean n dist = do
  xs <- sequence (replicate n dist)
  return (sum xs)
Run Code Online (Sandbox Code Playgroud)

除了它有点复杂.实际的代码我感兴趣的是函数likelihoodWeighting此Github上回购.

我注意到运行时间非线性地缩放n.特别是,一旦n超过某个值,它就会达到内存限制,并且运行时间会爆炸.我不确定,但我认为这是因为sequence正在构建一长串的thunk,直到调用才会得到评估sum.

一旦我通过大约100,000个样本,该程序就会慢慢爬行.我想优化它(我的感觉是1000万个样本应该不是问题)所以我决定对它进行分析 - 但是我在理解分析器的输出方面遇到了一些麻烦.


剖析

我在一个main.hs运行我的函数的文件中创建了一个简短的可执行文件 这是做的输出

$ ghc -O2 -rtsopts main.hs
$ ./main +RTS -s
Run Code Online (Sandbox Code Playgroud)

我注意到的第一件事 - 它分配了近1.5 GB的堆,并将60%的时间花在垃圾收集上.这通常表明懒惰太多了吗?

 1,377,538,232 bytes allocated in the heap
 1,195,050,032 bytes copied during GC
   169,411,368 bytes maximum residency (12 …
Run Code Online (Sandbox Code Playgroud)

performance haskell strictness

23
推荐指数
2
解决办法
3145
查看次数

foldl比其严格的堂兄,foldl'更受欢迎吗?

Haskell有两个左侧折叠函数用于列表:foldl和"严格"版本foldl'.非严格的问题foldl是它构建了一个thunk的塔:

    foldl (+) 0 [1..5]
--> ((((0 + 1) + 2) + 3) + 4) + 5
--> 15
Run Code Online (Sandbox Code Playgroud)

这会浪费内存,如果列表中的项目太多,可能会导致堆栈溢出. foldl'另一方面,强制累加器在每个项目上.

但是,就我所知,foldl'语义上等同foldl.评估foldl (+) 0 [1..5]头部正常形式需要在某个时刻强制累加器.如果我们不需要头部正常形式,我们就不会foldl (+) 0 [1..5]开始评估.

有没有令人信服的理由,人们会想要foldl超过那个的行为foldl'

haskell fold strictness

22
推荐指数
2
解决办法
1186
查看次数

在Haskell中运算符&&严格吗?

例如,我有一个fnB :: a -> BoolfnA :: Bool返回之前没有意义的操作False.CI中可以将这两个操作组合在一个if块中:

if( fnA && fnB(a) ){ doSomething; }
Run Code Online (Sandbox Code Playgroud)

和C将保证fnBfnA返回false 之前不会执行.

但Haskell是惰性的,并且,通常也不能保证什么操作将首先执行,直到我们不使用seq,$!或别的东西,使我们的代码严格.一般来说,这就是我们需要快乐的事情.但是使用&&运算符,我希望fnBfnA返回结果之前不会对其进行求值.Haskell提供这样的保证&&吗?fnB即使fnA返回False,Haskell也会评估吗?

haskell logical-operators strictness

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

模式匹配中的评估顺序是否有任何保证?

下列

(&&) :: Bool -> Bool -> Bool
False && _ = False
True && False = False
True && True = True
Run Code Online (Sandbox Code Playgroud)

具有所需的短路特性False && undefined ? False.第一个子句在右边的参数中是非严格的,保证在尝试任何其他操作之前进行检查.

显然,如果我改变顺序甚至不发布功能,它仍然有效

both :: (Bool,Bool) -> Bool
both (True,False) = False
both (True, True) = True
both (False, _) = False

Prelude> both (False, undefined)
False
Run Code Online (Sandbox Code Playgroud)

但这实际上是由标准保证的吗?与条款的顺序不同,模式的评估顺序在这里并不十分清楚.在确定snd元素之前,我是否可以确定匹配(True,False)将在(False,_)确定后立即中止?

haskell pattern-matching strictness

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

严格可能在数据定义中

我看过很多会谈/阅读博客文章,你应该有严格的字段,data以避免各种性能问题,例如:

data Person = Person
    { personName     :: !Text
    , personBirthday :: !UTCTime
    }
Run Code Online (Sandbox Code Playgroud)

这对我来说很有意义.由于对该数据的函数操作是惰性的,因此不会牺牲可组合性.

但是,如果我添加一个Maybe字段:

data Person = Person
    { personName     :: !Text
    , personBirthday :: !UTCTime
    , personAddress  :: !(Maybe Address)
    }
Run Code Online (Sandbox Code Playgroud)

我将懒惰引入数据结构,毕竟Maybe是一个控制结构.是不是可以毫无价值地躲在Just构造函数后面?

但是,有严格Maybestrict或通过strict-base-types.但是根据反向依赖(strict,strict-base-types),它们并没有被广泛使用.

所以问题是:为什么Maybe在非控制数据定义中应该或不应该使用strict ?

haskell strictness

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