Re: Неправильный автомат.
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.05.07 22:24
Оценка: 14 (1)
Здравствуйте, Klapaucius, Вы писали:

Собсвтенно ответ на твой вопрос здесь
Автор: VladD2
Дата: 13.05.07
.

Так что отпиши баг-репорт, а сам используй void-функцию пока баг не поправят.

Но хочется сказать по пводу match-а и предупреждений. Все же так писать не хорошо. Лучше ставить вхождения матча с константными значениями перед вхождениями с открытым паттерном (т.е. с переменными, например BuffOut(n)). А вместо того чтобы делать проверки вроде "when n > 0" лучше добавлять вхождения проверяющие на "n < 0". Так что я бы написал твой код так:
using System;
using System.Console;
using Nemerle.Utility;
using System.Collections.Generic;

module Program
{
  private variant ST
  {
    | Scan
    | Lead
    | Gold
    | BuffOut {count : int;}
    | GoldOut 
    | LeadOut {count : int;}
  }

  public SelectWithTrain[T](this seq : IEnumerable[T],
    predicate : T -> bool,
    train : int = 5
  )
    : IEnumerable[T]
  {
    def queue = Nemerle.Collections.Queue(train);
    mutable state = ST.Scan();

    foreach(elem in seq)
    {
      def loop(s : ST) : void
      {
        | Scan => loop(if(predicate(elem)) ST.Gold() else ST.Lead()) 
        | Lead =>
          when (queue.Count >= train)
            _ = queue.Dequeue(); 
          queue.Enqueue(elem);
          state = ST.Scan()

        | Gold => loop(ST.BuffOut(queue.Count)) 
        | BuffOut(0) => loop(ST.GoldOut())
        | BuffOut(n) when n < 0 => throw Exception($"Хреновое состояние  BuffOut($n)!")
        | BuffOut(n) =>
          yield queue.Dequeue();
          loop(ST.BuffOut(n-1))
          
        | GoldOut =>
          yield elem;
          state = ST.LeadOut(train)

        | LeadOut(0) => state = ST.Scan()
        | LeadOut(n) when n < 0 => throw Exception($"Хреновое состояние  LeadOut($n)!")
        | LeadOut(n) =>
          if (predicate(elem)) 
            loop(ST.Gold()) 
          else 
          { 
            yield elem;
            state = ST.LeadOut(n-1)
          }
      }
      
      loop(state)
    }
  }

  Main() : void
  {
      def lst = [-1, 2, 3, -4, -5, -6, -7, -8, -9, -10, 11, -12, 13, 14, 15, -16];
      def iter = lst.SelectWithTrain(_ > 0, 2);
      // ожидаемый вывод [-1, 2, 3, -4, -5, -9, -10, 11, -12, 13, 14, 15, -16], но...
      WriteLine($[x | x in iter]); // здесь возникает исключение, о котором ниже.
      _ = ReadLine();
  }
}
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Неправильный автомат.
От: Klapaucius  
Дата: 12.05.07 16:03
Оценка:
Нижеследующий код выполняет, в двух словах, следующую работу: последовательность элементов преобразует в другую последовательность, которая состоит из элементов отвечающих некоторому условию и заданного кол-ва соседствующих с ними элементов.
Данный код компилируется без вопросов, с одним единственным предупреждением, касающимся матчинга (переписывание матчинга так, чтобы предупреждение исчезло ничего не меняет, так что к делу не относится.), но получившийся автомат не работает, выбрасывая исключение в рантайм.

using System;
using System.Console;
using Nemerle.Utility;
using System.Collections.Generic;

module Program
{
    private variant ST
    {
        | Scan
        | Lead
        | Gold
        | BuffOut {count : int;}
        | GoldOut 
        | LeadOut {count : int;}
    }

    public SelectWithTrain[T](this seq : IEnumerable[T],
        predicate : T -> bool,
        train : int = 5 
        ) : IEnumerable[T]
    {
        def queue = Nemerle.Collections.Queue(train);
        mutable state = ST.Scan();

        foreach(elem in seq)
        {
            def loop(s : ST)
            {
                | Scan => loop(if(predicate(elem)) ST.Gold() else ST.Lead()) 
                | Lead => {
                            when (queue.Count >= train)
                                _ = queue.Dequeue(); 
                            queue.Enqueue(elem);
                            ST.Scan()
                          }
                | Gold => loop(ST.BuffOut(queue.Count)) 
                | BuffOut(n) when n > 0 => { 
                            yield queue.Dequeue();
                            loop(ST.BuffOut(n-1))
                          }
                | BuffOut(0) => loop(ST.GoldOut())
                | GoldOut => { 
                            yield elem;
                            ST.LeadOut(train)
                          }
                | LeadOut(n) when n > 0 => { 
                            if (predicate(elem)) 
                                loop(ST.Gold()) 
                            else 
                            { 
                                yield elem;
                                ST.LeadOut(n-1)
                            }
                          }
                | LeadOut(0) => ST.Scan()
            }
            state = loop(state)
        }
    }

    Main() : void
    {
        def lst = [-1, 2, 3, -4, -5, -6, -7, -8, -9, -10, 11, -12, 13, 14, 15, -16];
        def iter = lst.SelectWithTrain(_ > 0, 2);
        // ожидаемый вывод [-1, 2, 3, -4, -5, -9, -10, 11, -12, 13, 14, 15, -16], но...
        WriteLine($[x | x in iter]); // здесь возникает исключение, о котором ниже.
    }
}


А вот и исключение:

System.InvalidProgramException was unhandled
Message: Common Language Runtime detected an invalid program.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re: Неправильный автомат.
От: Иванков Дмитрий Россия  
Дата: 12.05.07 16:32
Оценка:
Баг, должно быть сообщение о том, что yield нельзя использовать в локальных функциях.
Re[2]: Неправильный автомат.
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.05.07 21:44
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД>Баг, должно быть сообщение о том, что yield нельзя использовать в локальных функциях.


Исключение конечно всегда баг, но сообщение тут не причем.

yield допустим в локальных функциях. Считаетя, что локальные функции заменяют циклы.

Думаю, что проблема в данном случае в том, что компилятор не верно обрабатывает фукнцию с yield которая при этом возвращает еще и некоторое значение. Посторить ДКА при этом несколько сложнее нежели в случае с void-фунцией.

Попробовал переписать код так чтобы функция ничего не возвращала... и все заработало. Вот код:
using System;
using System.Console;
using Nemerle.Utility;
using System.Collections.Generic;

module Program
{
    private variant ST
    {
        | Scan
        | Lead
        | Gold
        | BuffOut {count : int;}
        | GoldOut 
        | LeadOut {count : int;}
    }

    public SelectWithTrain[T](this seq : IEnumerable[T],
        predicate : T -> bool,
        train : int = 5 
        ) : IEnumerable[T]
    {
        def queue = Nemerle.Collections.Queue(train);
        mutable state = ST.Scan();

        foreach(elem in seq)
        {
            def loop(s : ST) : void
            {
                | Scan => loop(if(predicate(elem)) ST.Gold() else ST.Lead()) 
                | Lead => {
                            when (queue.Count >= train)
                                _ = queue.Dequeue(); 
                            queue.Enqueue(elem);
                            state = ST.Scan()
                          }
                | Gold => loop(ST.BuffOut(queue.Count)) 
                | BuffOut(0) => loop(ST.GoldOut())
                | BuffOut(n) when n > 0 => { 
                            yield queue.Dequeue();
                            loop(ST.BuffOut(n-1))
                          }
                | GoldOut => { 
                            yield elem;
                            state = ST.LeadOut(train)
                          }
                | LeadOut(0) => state = ST.Scan()
                | LeadOut(n) when n > 0 => { 
                            if (predicate(elem)) 
                                loop(ST.Gold()) 
                            else 
                            { 
                                yield elem;
                                state = ST.LeadOut(n-1)
                            }
                          }
                | _ => throw Exception("Вообще такие вещи нужно обрабатвать по человечески!")
            }
            
            loop(state)
        }
    }

    Main() : void
    {
        def lst = [-1, 2, 3, -4, -5, -6, -7, -8, -9, -10, 11, -12, 13, 14, 15, -16];
        def iter = lst.SelectWithTrain(_ > 0, 2);
        // ожидаемый вывод [-1, 2, 3, -4, -5, -9, -10, 11, -12, 13, 14, 15, -16], но...
        WriteLine($[x | x in iter]); // здесь возникает исключение, о котором ниже.
        _ = ReadLine();
    }
}

Вывод:
[-1, 2, 3, -4, -5, -9, -10, 11, -12, 13, 14, 15, -16]
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Неправильный автомат.
От: Иванков Дмитрий Россия  
Дата: 13.05.07 08:32
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Иванков Дмитрий, Вы писали:


ИД>>Баг, должно быть сообщение о том, что yield нельзя использовать в локальных функциях.


VD>Исключение конечно всегда баг, но сообщение тут не причем.


VD>yield допустим в локальных функциях. Считаетя, что локальные функции заменяют циклы.


Ок, пусть допустим. Но не работает ни в одном из следующих случаев:
1) вызов происходит >= 2 раза
2) вызов рекурсивный
3) вызов из другой лок. ф-ии
4) вызов из другой лок. ф-ии объявленной через def ... and ...
5) тип результата не void

Т.е. работает только в случае если можно убрать объявление ф-ии и заменить единственный вызов ее телом.

Мне кажется компиллятор должен честно сказать, что пока что yield в локальных функциях не поддерживается.
Re[4]: Неправильный автомат.
От: Иванков Дмитрий Россия  
Дата: 13.05.07 13:30
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД>Здравствуйте, VladD2, Вы писали:


VD>>yield допустим в локальных функциях. Считаетя, что локальные функции заменяют циклы.


ИД>Но не работает ни в одном из следующих случаев:

ИД>2) вызов рекурсивный

За исключением хвостовой рекурсии.

Пожалуй пора просуммировать и зарепортить
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.