Nano Hash - криптовалюты, майнинг, программирование

Объединение числа в список на Прологе

Итак, я работаю над домашним заданием, это должен быть четырехфункциональный калькулятор, принимающий список строк [три, раз, два], например, и выводящий число. Он рассматривает только числа от одного до двадцати в своем исходном списке. Следующий код полностью принадлежит мне. Он работает до того момента, когда он принимает последний элемент в списке (который я использовал для его проверки, но проблема заключается в любом из входных данных) в нумерации, а затем не будет унифицировать.

calculator([twenty, times, three, plus, five, divided_by, two],Total).

Я знаю, что решение должно быть простым, но я еще недостаточно разбираюсь в Прологе, чтобы понять его.

Мой вопрос: как мне исправить мой код, чтобы он работал так, как я хочу?

calculator(X,Total):-
   numberize(X,L),
   reverse(L,L1),
   func(L1,Total).

numberize([X,Y|T],L):-
   str2num(X,X1),
   numberize(T,[Y,X1|L]).

numberize([X],L):-
   str2num(X,X1),
%somehow add on the X1 to the front of L without any errors and it's golden
/*Whatever that line is*/L is [X1|L].

func([X1,X,Z1|T], Total):-
   (X == times, times(X1,Z1,Ttl));
   (X == plus, plus(X1,Z1,Ttl));
   (X == divided_by, divided_by(X1,Z1,Ttl));
   (X == minus, minus(X1,Z1,Ttl)),
   func([Ttl|T],Total).

str2num(one, X):- X is 1.
str2num(two, X):- X is 2.
str2num(three, X):- X is 3.
str2num(four, X):- X is 4.
str2num(five, X):- X is 5.
str2num(six, X):- X is 6.
str2num(seven, X):- X is 7.
str2num(eight, X):- X is 8.
str2num(nine, X):- X is 9.
str2num(ten, X):- X is 10.
str2num(eleven, X):- X is 11.
str2num(twelve, X):- X is 12.
str2num(thirteen, X):- X is 13.
str2num(fourteen, X):- X is 14.
str2num(fifteen, X):- X is 15.
str2num(sixteen, X):- X is 16.
str2num(seventeen, X):- X is 17.
str2num(eighteen, X):- X is 18.
str2num(nineteen, X):- X is 19.
str2num(twenty, X):- X is 20.
times(X,Y,Prod):-
   Prod is X*Y.

plus(X,Y,Sum):-
   Sum is X+Y.

divided_by(X,Y,Quo):-
   Quo is X/Y.

minus(X,Y,Dif):-
   Dif is X-Y.
21.02.2014

  • Должны ли мы заботиться о приоритете операторов? Другими словами, должно ли 3 плюс 4 умножить на 5 равно 23 или 35? 21.02.2014
  • @ATS Им все равно. Я знаю это из примеров в этом вопросе (от одноклассника ОП?): com/questions/21923917/calc-2-предикат/21924965 21.02.2014
  • Да нам это было не нужно. Это другой пример, который нам привели, поэтому я полагаю, что @SergeyDymchenko прав, говоря, что другой постер — одноклассник. Но нет, я этого не делал, все (должно было) работать так, как у меня было. 22.02.2014
  • str2num(one,1). предпочтительнее и проще, чем str2num(one,X) :- X is 1.. Аналогично для других чисел. 22.02.2014

Ответы:


1

Небольшое замечание по стилю: используйте факты для str2num/2: просто str2num(one, 1). вместо str2num(one, X):- X is 1. и т. д. Дополнительным преимуществом является то, что теперь предикат можно использовать в обоих направлениях, например str2num(Word, 1).

Что касается основного вопроса, то вы почти правы.

Весь предикат numberize может быть таким простым:

numberize([X], [N]) :-
    str2num(X, N).
numberize([X, Op | T], [N, Op | NewT]) :-
    str2num(X, N),
    numberize(T, NewT).

Давайте проверим это:

?- numberize([one, plus, two, minus, three], L).
L = [1, plus, 2, minus, 3] 

Но вам нужно удалить вызов reverse из calculator:

calculator(X,Total):-
    numberize(X,L),
    func(L,Total).

У вас почти правильный предикат func. Одна проблема: в Прологе у вас должны быть фигурные скобки вокруг дизъюнкции:

func([X1,X,Z1|T], Total):-
    (
        X == times, times(X1,Z1,Ttl)
    ;
        X == plus, plus(X1,Z1,Ttl)
    ;
        X == divided_by, divided_by(X1,Z1,Ttl)
    ;
        X == minus, minus(X1,Z1,Ttl)
    ),
    func([Ttl|T],Total).

Вторая проблема: когда ваш список уменьшится до одного числа (подумайте, как func([1,plus,2], Total) вызовет func([3], Total), предикат не сработает. Все, что вам нужно исправить, это правило, согласно которому Total списка с одним числом является самим числом:

func([X], X).

Теперь все работает:

?- calculator([one, plus, two], Total).
Total = 3 

?- calculator([one, plus, two, minus, four], Total).
Total = -1 
21.02.2014
  • @Throsby Также обратите внимание, что, если ответ находится в пределах вашего диапазона переведенных чисел, вы можете перевести его обратно, чтобы получить ?- calculator([one, plus, four, minus, three], Total). Total = two. 21.02.2014

  • 2

    Я бы подошел к этому, начав с определения грамматики для арифметических выражений. «Стандартный» способ определения грамматик — леворекурсивный. Поскольку в прологе выполняется рекурсивный разбор по спуску, грамматика не может быть леворекурсивной. Каждая итерация должна что-то удалять из потока токенов, чтобы не попасть в смертельную спираль бесконечной рекурсии. Вот моя нелевая рекурсивная грамматика для калькулятора с 4 ударами, такого как ваш:

    expression : multiplicative_expression '+' expression
               | multiplicative_expression '-' expression
               | multiplicative_expression
               ;
    
    multiplicative_expression : factor '*' multiplicative_expression
                              | factor '/' multiplicative_expression
                              | factor '%' multiplicative_expression
                              | factor
                              ;
    
    factor : '-' value
           | '(' expression ')'
           | value
           ;
    
    value : number
    

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

    operator( plus       , additive       , '+'   ) .
    operator( minus      , additive       , '-'   ) .
    operator( times      , multiplicative , '*'   ) .
    operator( divided_by , multiplicative , '/'   ) .
    operator( modulo     , multiplicative , 'mod' ) .
    

    И карта слов в числа:

    number_word( zero     , 0 ).
    number_word( one      , 1 ).
    ...
    number_word( nineteen , 19 ) .
    number_word( twenty   , 20 ) .
    

    И нам нужен наш предикат интерфейса, calculate/2:

    %--------------------------------------------------------------------
    % we can calculate a result if Expr is a valid expression
    % that consumes all the available tokens in the token stream
    %---------------------------------------------------------------------
    calculate(Expr,Result) :- expr( Expr , Result , [] ) .
    

    Это вызывает «начальный символ» грамматики, expr/3. expr/3 (и другие рабочие предикаты) в значительной степени являются прямыми переформулировками грамматики с дополнительным требованием, что они должны возвращать неиспользованную часть потока входных токенов. Разбор считается успешным, если в конце дня поток токенов пуст:

    expr( Xs , Result , Tail ) :-       % per the grammar, an expression is
      mult( Xs , LHS , [Sym|X1] ) ,     % - a multiplicative expression, followed by
      operator( Sym , additive , Op ) , % - an infix additive operator, followed by
      expr( X1 , RHS , X2 ) ,           % - another expression
      Term =.. [Op,LHS,RHS] ,           % * in which case, we construct the proper prolog structure
      Result is Term ,                  % * in which case, we evaluate the result in the usual way
      Tail = X2                         % * and unify any remaining tokens with the Tail
      .                                 %
    expr( Xs , Result , Tail ) :-       % alternatively, an expression is simply
      mult( Xs , Result , Tail )        % - a single multiplicative expression
      .                                 %
    

    Рабочий предикат для мультипликативных терминов mult/3 в значительной степени идентичен прямому повторению грамматики:

    mult( Xs , Result, Tail ) :-              % a multiplicative expression is
      factor( Xs , LHS , [Sym|X1] ) ,         % - a factor, followed by
      operator( Sym , multiplicative , Op ) , % - an infix multiplicative operator, followed by
      mult( X1 , RHS , X2 ) ,                 % - another factor
      evaluate( Op , LHS , RHS , Result ) ,   % * in which case, we evalute the result in the usual way
      Tail = X2                               % * and unify any remaining tokens with the tail
      .                                       %
    mult( Xs , Result , Tail ) :-             % alternatively, a multiplicative expression is simply
      factor( Xs , Result , Tail )            % - a single factor
      .                                       %
    

    Наконец, поскольку мы не возимся с операциями с более высоким приоритетом, такими как унарный минус, возведение в степень или круглые скобки, которые изменяют приоритет операций, множитель — это просто числовое слово, которое можно преобразовать в целочисленное значение:

    factor( [X|Xs] , Value , Xs ) :- % a factor is simply
      number_word(X,Value)           % - a number value (in our case, a word that we convert to an integer)
      .
    

    и простой помощник для оценки каждого подвыражения по мере необходимости:

    evaluate( Op , LHS , RHS , Result ) :- % to evaluate an infix term,
      Term =.. [Op,LHS,RHS] ,              % - use univ to convert to the correct prolog structure, and
      Result is Term                       % evaluate it as the result
      .                                    %
    
    22.02.2014
  • Красивый ответ, но я искал исправление, а не лучшую программу. Я должен был принять первый ответ раньше. Извините, но спасибо! 23.02.2014
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..