<p>让我们先来处理第一个函数:</p>
<pre><code>def segment(text):
"Return a list of words that is the best segmentation of text."
if not text: return []
candidates = ([first]+segment(rem) for first,rem in splits(text))
return max(candidates, key=Pwords)
</code></pre>
<p>它接受一个单词并返回它可能是的最可能的单词列表,因此它的签名将是<code>static IEnumerable<string> segment(string text)</code>。显然,如果<code>text</code>是一个空字符串,那么它的结果应该是一个空列表。否则,它创建一个递归列表理解,定义可能的候选单词列表,并根据其概率返回最大值。在</p>
^{pr2}$
<p>当然,现在我们要翻译<code>splits</code>函数。它的任务是返回一个单词开头和结尾的所有可能元组的列表。翻译起来相当简单:</p>
<pre><code>static IEnumerable<Tuple<string, string>> splits(string text, int L = 20)
{
return from i in Enumerable.Range(1, Math.Min(text.Length, L))
select Tuple.Create(text.Substring(0, i), text.Substring(i));
}
</code></pre>
<p>接下来是<code>Pwords</code>,它只是对输入列表中每个单词的<code>Pw</code>的结果调用<code>product</code>函数:</p>
<pre><code>static double Pwords(IEnumerable<string> words)
{
return product(from w in words select Pw(w));
}
</code></pre>
<p>而且<code>product</code>非常简单:</p>
<pre><code>static double product(IEnumerable<double> nums)
{
return nums.Aggregate((a, b) => a * b);
}
</code></pre>
<h2>附录:</h2>
<p>查看完整的源代码,很明显,Norvig打算将<code>segment</code>函数的结果存储起来以提高速度。以下是提供这种加速的版本:</p>
<pre><code>static Dictionary<string, IEnumerable<string>> segmentTable =
new Dictionary<string, IEnumerable<string>>();
static IEnumerable<string> segment(string text)
{
if (text == "") return new string[0]; // C# idiom for empty list of strings
if (!segmentTable.ContainsKey(text))
{
var candidates = from pair in splits(text)
select new[] {pair.Item1}.Concat(segment(pair.Item2));
segmentTable[text] = candidates.OrderBy(Pwords).First().ToList();
}
return segmentTable[text];
}
</code></pre>