/// <summary>Parse a Sentence.</summary>
        /// <remarks>
        /// Parse a Sentence.  It is assumed that when this is called, the pparser
        /// has already been called to parse the sentence.
        /// </remarks>
        /// <param name="words">The list of words to parse.</param>
        /// <returns>true iff it could be parsed</returns>
        public virtual bool Parse <_T0>(IList <_T0> words)
            where _T0 : IHasWord
        {
            nGoodTrees.Clear();
            int numParsesToConsider = numToFind * op.testOptions.fastFactoredCandidateMultiplier + op.testOptions.fastFactoredCandidateAddend;

            if (pparser.HasParse())
            {
                IList <ScoredObject <Tree> > pcfgBest   = pparser.GetKBestParses(numParsesToConsider);
                Beam <ScoredObject <Tree> >  goodParses = new Beam <ScoredObject <Tree> >(numToFind);
                foreach (ScoredObject <Tree> candidate in pcfgBest)
                {
                    if (Thread.Interrupted())
                    {
                        throw new RuntimeInterruptedException();
                    }
                    double depScore       = DepScoreTree(candidate.Object());
                    ScoredObject <Tree> x = new ScoredObject <Tree>(candidate.Object(), candidate.Score() + depScore);
                    goodParses.Add(x);
                }
                nGoodTrees = goodParses.AsSortedList();
            }
            return(!nGoodTrees.IsEmpty());
        }