2011-05-07 96 views
2

我有這個功能F#迭代:類型「單元」不匹配的類型「字符」

let items = ['a'; 'a'; 'a'; 'a'; 'b'; 'b'; 'a'; 'a'; 'c'; 'd'; 'd'; 'e'; 'e';] 

open System 
let rng = new Random() 

let randomSelect list toget = let randomList k len = List.init k (fun _ -> rng.Next(1,len)) 
           let getK l k = List.nth l k 
           let primeGet = getK list 
           List.length list 
           |> randomList toget 
           |> List.iter (fun i -> primeGet i) 

let res23 = randomSelect items 3 

,但由於某種原因,函數需要一個單元列表,而不是一個通用的一個

類型「單元」不匹配的類型「字符」

爲什麼會出現這種情況?

回答

5

正如其他人已經指出的那樣,你可能想用map而不是iter。這會起作用,但這不是特別有效的實施。下面是一個使用列表解析來實現它的另一種方式:

let randomSelect list toget = 
    [ let arr = list |> Array.ofList 
    for _ in 1 .. toget do 
     yield arr.[rng.Next(arr.Length)] ] 

......這能使用map功能也寫的,但我覺得理解語法更具可讀性:

let randomSelect list toget = 
    let arr = list |> Array.ofList 
    [ 1 .. toget ] |> List.map (fun _ -> arr.[rng.Next(arr.Length)]) 

爲了避免索引問題,函數首先將列表(作爲參數給出)轉換爲數組。如果你需要更多的元素,這將會更有效率。對於較少數量的元素,僅使用列表和索引List.nth應該沒問題。

該片段然後生成(使用1 .. toget)合適的長度的序列,併產生一個新的隨機元件對該輸入序列中的每個元素。輸入序列中的值不是必需的 - 它們只是用於生成一些序列。

3

因爲List.iter預計返回unit的函數和函數返回fun i -> primeGet iunit當且僅當listunit列表。

請注意,即使您的代碼編譯完成,它也不會執行任何操作,因爲List.iter返回unit,並且僅用於函數的副作用(在此情況下不存在)。我的猜測是,你可能想使用map代替iter,它會返回的primeGet結果列表。這也可以解決你的類型錯誤。

0

一個評論:

let getK l k = List.nth l k 
    let primeGet = getK list 

List.nth是線性運算。由於F#列表是一個鏈表,它沒有位置的概念。並在你的代碼primeGet中使用了一個循環,這使得你的代碼的運行時間是二次的。

+0

我知道它是沒有效率的。但我想先讓它工作,然後讓它變得更好 – Marcom 2011-05-07 18:33:29