2013-02-10 132 views
2

我想學習標準毫升的新球衣,但我不明白如何迭代列表。如何迭代列表?

我想創建一個函數,它接受一個值和一個函數列表,並返回另一個字符串列表,如果當前函數在給定值時返回true。

功能就像這樣('a -> bool) * string,即一對函數和它的名字串。

該函數是一個curried函數,因此它的定義類似於「fun it x xs」。

我想非遞歸地做到這一點。

任何人都可以幫助我開始嗎?

+0

爲什麼你想這樣做,非遞歸? ML的列表結構自然是遞歸的。 – voithos 2013-02-10 23:21:40

+0

我很確定在SML中沒有「非遞歸」的東西。沒有循環控制流程結構。如下所述,你可以使用foldr,但這只是一個使用遞歸的高階函數。 – dbmikus 2013-06-14 14:25:25

+1

你可以在標準ML中編寫命令式的代碼,但並不漂亮。既有'while'又有'ref',例如'val x = ref 0; val_ = while!x <10 do x:=!x + 1'。 – 2013-08-06 11:27:28

回答

0

一個自然而直接的函數可以很容易地用遞歸寫出來。

fun itr x fs = 
    case fs 
    of [] => [] 
    | (f, s) :: fs' => if f x 
         then s :: itr x fs' 
         else itr x fs' 

或者,如果你不想在你的函數明確遞歸,您可以使用foldr

fun itr x fs = 
    List.foldr (fn ((f, s), ss) => 
    if f x 
    then s :: ss 
    else ss) [] fs 

而且,itr是不是一個非常翔實的名字,所以你可能想選擇一個不同的,更好地描述了什麼是你正在嘗試做的。

0

所以,如果我理解正確的話,你希望能夠調用你的函數是這樣的:

itr 
    3 
    [ ((fn i => i > 3), "greaterThanThree"), 
     ((fn i => i mod 2 = 1), "odd"), 
     ((fn i => 12 mod i = 0), "dividesTwelve") 
    ] 

和得到的結果一樣["odd", "dividesTwelve"](因爲odddividesTwelve是兩個功能使用時就返回true3)。

我有這個權利嗎?

因此,我們可以通過書寫開始:

(* Given a value and a list of named Boolean functions, returns a list of the names of the 
* functions that return true for value. 
*) 
fun itr value namedFunctions = 
    ... 

既然你說你想「做這個非遞歸」,我認爲你的意思是,你要使用的列表功能標準ML基礎庫,允許您通過提供獨立處理列表元素的函數來處理列表;這些函數當然是使用遞歸實現的,但是如果itr只是代表它們,那麼itr本身不需要遞歸。

鑑於這些要求,我看到兩種方法。


一種方法是通過使用List.filtersee List.filter documentation here)得到的只是關於value調用時返回true的的namedFunctions元素開始。要做到這一點,我們需要一個函數,命名函數(一('a -> bool) * string,其中'avalue類型),並返回true如果命名的函數返回true;那就是:

(* A function that, given a named Boolean function, returns whether it returns true for 
* value. 
*) 
fn (f, _) => f value 

來讓我們叫List.filter像這樣:

(* A list of the elements of namedFunctions that return true for value. *) 
List.filter (fn (f, _) => f value) namedFunctions 

一旦我們有了這一點,我們需要使用List.mapsee List.map documentation here),以獲得每個功能的只是名字:

(* A list of the names in namedFunctions that return true for value. *) 
List.map #2 (List.filter (fn (f, _) => f value) namedFunctions) 

(其中#2是提取元組或記錄的組件2的函數;在命名爲f聯合,#2 namedFunction是名稱)。

將其組合在一起:

(* Given a value and a list of named Boolean functions, returns a list of the names of the 
* functions that return true for value. 
*) 
fun itr value namedFunctions = 
    List.map #2 (List.filter (fn (f, _) => f value) namedFunctions) 

另一種方法是既過濾和映射組合到單個步驟中,通過使用List.mapPartial(見List.mapPartial documentation here)。相反,正是我們想要的元素用一個函數,命名函數,並返回一個布爾值,然後將它們轉換成我們希望通過使用一個函數,命名函數,並返回其名稱形式的第一選擇,我們可以結合步驟通過使用帶有命名函數的函數,並且僅當我們需要時返回其名稱

標準ML,當我們想要的,我們用option來表示的值並不總是存在的;例如,string option手段「是一個字符串,有或全無」(see Option.option documentation here;值得注意的是,雖然它的記錄爲Option.option,它也可作爲剛剛option)。所以,這裏的,需要一個命名函數返回只有當它爲value返回true其名稱的功能:

(* A function that, given a named Boolean function, returns its name if it returns true 
* for value, and nothing if it returns false. 
*) 
fn (f, name) => if f value then SOME name else NONE 

這種功能被稱爲「部分功能」 —它只是的一部分返回一個值其領域—,我們可以使用List.mapPartial檢索其結果只有那些地方都返回一個情況:

(* Given a value and a list of named Boolean functions, returns a list of the names of the 
* functions that return true for value. 
*) 
fun itr value namedFunctions = 
    List.mapPartial (fn (f, name) => if f value then SOME name else NONE) namedFunctions 

一般來說,要應用到List.map的結果的任何時間或反之亦然,您可以使用List.mapPartial將兩個步驟組合在一起。 (在任何給定的情況下,但是,它可能是也可能不是一個好主意,這樣做。我推薦哪一個更清晰。)