11.3.4 f# 中的延遲值
f# 中的延遲值(lazy value)是通過延遲計算表示的,就是說,只有在值需要時才進行計算。在上一節,我們用 c# 函式實現了類似的功能,而延遲值自動只計算一次,並能記住結果。
探索此功能的最佳方法是在 f# interactive 中進行。清單 11.16 用指令碼進行了演示。
清單編號的錯誤再次出現了.
清單 11.16 介紹延遲值 (f# interactive)
> let foo(n) =
printfn "foo(%d)" n
n <= 10;;
val foo : int ¨c> bool
> let n = lazy foo(10);; | [1]
val n : lazy= value is notcreated. |
> n.value;; <-- 呼叫 foo,得到結果
foo(10) | [2]
val it : bool = true |
> n.value;; <-- 立即返回結果
val it : bool = true [3]
我們首先寫乙個類似於 c# 的 foo 方法的函式,它通過寫到控制台跟蹤計算的時間;第二個命令使用 f# 的 lazy 關鍵字[1]。如果表示式用lazy 標記,那麼,這個表示式不會立即計算,會被打包成延遲值。從輸出可以看到,foo 函式還未呼叫,建立的值為lazy型別,表示可以計算出布林值的延遲值。
在下一行,可以看到這個延遲值有乙個成員,value [2],這個屬性執行延遲計算,在這裡,就是呼叫 foo 函式。最後乙個命令再次訪問 value [3],不會重新計算。如果看一下輸出,就會發現 foo 函式並未呼叫。這就是說,我們可以清楚地看到,lazy<'t> 是可變型別。如果我們使用無***的純函式式的函式,作為其引數,就不能觀察到這個現象。
在前幾章,我們已經強調過用這種函式式方式檢視資料型別,已經發現,在處理型別時,知道需要哪種操作,是很有用的。現在,我們就以這種觀點來審視一下延遲值。
使用操作指定延遲值
如果 f# 語言沒有 lazy 關鍵字,並且不允許寫有屬性的物件,可能會需要兩個操作,乙個用於構建延遲值,另乙個提取實際值:
val create : (unit -> 't) ->lazy<'t>
val force : lazy<'t> ¨c> 't
可以看到,create 操作的引數是乙個函式值,包裝在 lazy<'t> 值當中。在函式式程式設計中,存在表示延遲計算還有其他型別,所以,當函式的引數為 unit -> 't 型別的函式,返回型別為泛型時,型別可能表示成延遲計算。force 操作的簽名甚至更簡單,只是簡單地從打包它的型別中提取實際值。這個簽名並沒有告訴我們實際值是如何打包的,但是,因為有 force 操作,我們總是可以提取它。
在下一章我們將看到,在函式式程式設計中,就能夠處理基本操作而言,型別的這種抽象描述是有用的。雖然 f# 提供了處理延遲值的方法,比使用函式更方便,但是,了解基本操作(primitive operations)還是很有幫助的。
我們開始討論延遲值的動機,是不會自己實現邏輯或者運算子,計算右手邊的引數值,要看是否需要,何時需要。現在,我們將再嘗試用延遲值的新知識武裝一下。
如何理解ANOVA中的F值與P值
anova analysis of variance 方差分析,曾經以為它是乙個多麼複雜的簡寫。一 理解f分布 要理解f分布,就要先理解卡方分布,要理解卡方分布,就要先理解正態分佈。1.正態分佈的概率密度函式的表示式 畫出它的影象 集中分布在隨機變數的均值附近,對稱 2.卡方分布 如果有n個服從正態...
關於最大值的設定0x3f3f3f3f
在演算法競賽中,我們常常需要用到乙個 無窮大 的值,對於我來說,大多數時間我會根據具體問題取乙個99999999之類的數 顯得很不專業啊!在網上看別人 的時候,經常會看到他們把inf設為0x7fffffff,奇怪為什麼設乙個這麼奇怪的十六進製制數,一查才知道,因為這是32 bit int的最大值。如...
Hibernate中的延遲載入
最近因為給新員工寫例子用到hibernate,才發現自己對hibernate的理解也非常有限啊.複雜的hql語言我寫不出來,還遇到了很多詭異的問題.在寫例子的過程中最困擾我的是hibernate的延遲載入特性.眾所周知,到了hibernate3.0以後,關聯關係的物件預設都是使用延遲載入,例如時.但...