【问题标题】:Conditional writing in PrologProlog中的条件写入
【发布时间】:2022-11-16 11:02:54
【问题描述】:

我有带有航班时刻表的Prolog 数据库。这是它的样子:

fly(id, from, to, days(1, 0, 1, 0, 1, 0, 1)).

如您所见,days 谓词中有 7 个值 - 从星期一到星期日。我想做的是每天打印,值是1,但只打印成文本。我试图使用 if - else 声明,但在这种情况下它不起作用:

(   
        A = 1 -> write(monday), nl;
        (
            B = 1 -> write(tuesday), nl;
            (
                C = 1 -> write(wednesday), nl;
                (
                    D = 1 -> write(thursday), nl;
                    (
                        E = 1 -> write(friday), nl;
                        (
                            F = 1 -> write(saturday), nl;
                            (
                                G = 1 -> write(sunday), nl
                            )
                        )
                    )
                )
            )
        )
    )

例如,它应该打印 4 天:

monday
wednesday
friday
sunday

我怎样才能做到这一点?

【问题讨论】:

    标签: prolog


    【解决方案1】:

    我找到了一种方法,基本上,您需要创建 2 个列表。第一个是你的日子,第二个是日子的名字。然后,您需要迭代它们,但是,由于在 Prolog 中没有 loop 结构,您必须使用递归函数来完成。

    这是我的实现方式:

    iterate_weeks([], _).
    iterate_weeks([H|T], [X|Y]) :- H = 1, write(X), nl, iterate_weeks(T, Y).
    iterate_weeks([H|T], [_|Y]) :- H = 0, iterate_weeks(T, Y).
    
    print_fly_days(From, To):- 
        fly(_, From, To, _, _, days(A,B,C,D,E,F,G)),
        L = [A,B,C,D,E,F,G],
        T = [monday, tuesday, wednesday, thursday, friday, saturday, sunday],
        iterate_weeks(L, T).
    

    【讨论】:

    • Prolog 中没有循环结构,您必须使用递归函数来实现。“ - *眨眼*就像说没有土豆所以你必须吃薯条。顶部有一个名称,一些重复的代码,然后你跳回顶部。这就是循环的结构和它们的行为方式,因为递归正在循环。
    【解决方案2】:

    使用术语扩展,方便地将天数映射为整数:

    :- nb_setval(day_counter, 1).
    
    % Silence warnings
    :- discontiguous day_int/2.
    :- discontiguous int_day/2.
    
    % Don't actually need day_int for this example, but still nice to show
    term_expansion(day(Day), [int_day(I, Day), day_int(Day, I)]) :-
        nb_getval(day_counter, I),
        I1 is I + 1,
        nb_setval(day_counter, I1).
    
    day(monday).
    day(tuesday).
    day(wednesday).
    day(thursday).
    day(friday).
    day(saturday).
    day(sunday).
    
    days7_names(Days7, DayNames) :-
        findall(I, arg(I, Days7, 1), Is),
        maplist(int_day, Is, DayNames).
    

    swi-prolog 中的结果:

    ?- days7_names(day(0,1,0,1,0,0,1), Ns).
    Ns = [tuesday, thursday, sunday].
    

    【讨论】:

      【解决方案3】:

      在 APL 中,使用指标的布尔数组从数组中进行选择是 compress 操作:

           1 0 1 0 1 0 1 / 'Mon' 'Tue' 'Wed' 'Thu' 'Fri' 'Sat' 'Sun'
      ┌→────────────────────────┐
      │ ┌→──┐ ┌→──┐ ┌→──┐ ┌→──┐ │
      │ │Mon│ │Wed│ │Fri│ │Sun│ │
      │ └───┘ └───┘ └───┘ └───┘ │
      └∊────────────────────────┘
      

      我看不到 Prolog 有什么方便的东西,但你可以:

      day_name(days(1, _, _, _, _, _, _), mon).
      day_name(days(_, 1, _, _, _, _, _), tue).
      day_name(days(_, _, 1, _, _, _, _), wed).
      day_name(days(_, _, _, 1, _, _, _), thu).
      day_name(days(_, _, _, _, 1, _, _), fri).
      day_name(days(_, _, _, _, _, 1, _), sat).
      day_name(days(_, _, _, _, _, _, 1), sun).
      
      days_names(Day, Names) :-
          findall(Name, day_name(Day, Name), Names).
      

      例如

      ?- days_names(days(1, 0, 1, 0, 1, 0, 1), Names).
      Names = [mon, wed, fri, sun]
      

      另一种选择是pairs_keys_values/3,使用布尔值和名称来获得对[1-mon, 0-tue, 1-wed],用include/3过滤1-_,然后取消配对。它的行数更少并且避免了 findall,但不是很清楚。

      【讨论】:

        猜你喜欢
        • 2014-05-09
        • 1970-01-01
        • 1970-01-01
        • 2011-06-11
        • 1970-01-01
        • 2022-11-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多