Lisp-подобного класса список.


Итак, вот мой код:

    public class NList : SExp, IEnumerable<Object>
{
    private Object _car;
    private NList _cdr;

    IEnumerator<Object> IEnumerable<Object>.GetEnumerator()
    {
        return new NListEnumerator(this);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return new NListEnumerator(this);
    }

    public object car ()
    {
        return _car;
    }

    public NList cdr ()
    {
        return _cdr;
    }

    public NList cons (object o)
    {
        return new NList(o, this);
    }

    public NList() // empty list
    {

    }

    public NList(List<Object> lst)
    {
        if (lst.Count == 1)
        {
            this._car = lst[0];
            this._cdr = null;
        }
        else
        {
            this._car = lst[0];
            this._cdr = new NList(lst.GetRange(1, lst.Count - 1));
        }
    }

    public NList (Object fst)
    {
        this._car = fst;
        this._cdr = null;
    }

    public NList (Object fst, NList rst)
    {
        this._car = fst;
        this._cdr = rst;
    }

    public object Last()
    {
        NList list = this;
        while(list.cdr() != null)
        {
            list = list.cdr();
        }
        return list.car();
    }

    public int Count { get { return this.length(); } }

    public int length()
    {
        if (this._car == null && this._cdr == null) return 0;
        NList list = this;
        int len = 1;
        while(list.cdr() != null)
        {
            list = list.cdr();
            len++;
        }       
        return len;
    }

    public NList cddr()
    {
        return this.cdr().cdr();
    }

    public object cadr()
    {
        return this.cdr().car();
    }

    public object elm(int k)
    {
        if(k == 0) return car();
        NList list = cdr();
        for(int i = 1; i < k; i++, list = list.cdr()) ;
        return list.car();
    }


    public NList append(NList lst)
    {
        NList lst1 = this;
        NList lst2 = lst;
        if (this._car == null && this._cdr == null)
            return lst2;
        foreach(var e in Reverse(lst1))
        {
            lst2 = lst2.cons(e);
        }
        return lst2;
        //return lst1.Aggregate(lst2, (NList acc, object b) => acc);
    }

    public static NList Reverse(NList lst)
    {
        NList l = lst;
        NList res = null;
        while(l != null)
        {
            res = new NList(l.car(), res);
            l = l.cdr();
        }
        return res;
    }

    public override string ToString ()
    {
        if (this._car == null && this._cdr == null) return "()";
        string s = "(";
        for(int i = 0; i<this.Count-1; i++)
        {
            s+=this.elm(i).ToString() + " ";
        }
        s+=this.Last().ToString() + ")";
        return s;
    }
    public NObj[] ToNObjArray()
    {
        NObj[] a = new NObj[this.Count];
        int k = 0;
        foreach (var e in this)
        {
            a[k] = (e as NObj);
            k++;
        }
        return a;
    }
    public object[] ToArray()
    {
        object[] a = new object[this.Count];
        int k = 0;
        foreach(var e in this)
        {
            a[k] = e;
            k++;
        }
        return a;
    }
}

public class NListEnumerator : IEnumerator<Object>, IEnumerator
{
    NList list;
    NList tmp;
    public void Dispose()
    {
    }
    public NListEnumerator(NList list)
    {
        this.list = list;
        this.tmp = list.cons(null);
    }

    public object Current
    {
        get { return tmp.car(); }
    }

    public bool MoveNext()
    {
        tmp = tmp.cdr();
        return (tmp != null);
    }

    public void Reset()
    {
        tmp = list.cons(null);
    }
}

Я даже испугался, что у меня нет отдельного класса для простой пары (например: не завершено должным образом списки (1 . 2), (а . б)). Я должен создать отдельный класс (и интерфейс для обоих классов), или я должен попытаться расширить этот?

ТИА.



606
3
задан 12 апреля 2011 в 08:04 Источник Поделиться
Комментарии
2 ответа

Есть серьезный недостаток в обработке пустого списка. Пользователь будет ожидать, что эти определения эквивалентны, но они не:

Nlist n1 = new NList("x");
Nlist n2 = new NList("x", new NList());

Я настоятельно рекомендую иметь явную подкласс для пустого списка (возможно, одноэлементный) и запретить null для _cdr.

2
ответ дан 13 апреля 2011 в 06:04 Источник Поделиться


Я должен создать отдельный класс (и интерфейс для обоих классов), или я должен попытаться расширить этот?

В настоящий Lisp нет отдельного представительства для списков. Список-это просто цепь из точечных пар, на самом деле. Так что, я думаю, лучше изменять исходный класс и позволяют выделить списка CDR в что-нибудь другое, чем ПВ.

Кстати, почему бы не использовать свойства для этого:

public object car ()
{
return _car;
}

public NList cdr ()
{
return _cdr;
}

Также, если у вас уже есть SExp класса, это может быть хорошей идеей, чтобы вернуться SExp вместо объекта здесь.

1
ответ дан 13 апреля 2011 в 08:04 Источник Поделиться