2011-05-07 86 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