Prolog中的复合术语和列表

时间:2016-04-24 23:49:02

标签: list prolog term

为什么复合术语在性能方面优于列表? 例如,

matrix(row(1,2,3),row(1,2,3),row(1,2,3))

优于

[[1,2,3],[1,2,3],[1,2,3],[1,2,3]]

谢谢!

3 个答案:

答案 0 :(得分:6)

首先,要明确一点:列表 是一种复合词。

要查看列表是什么,请使用 import java.util.Scanner; import java.text.DecimalFormat; public class Candel { public static void main(String[] args) { Scanner sc = new Scanner(System.in); double candleCost, shippingCost; int shippingType; candleCost = getCandlecost(); shippingType = getShippingType(); shippingCost = getShippingCost(candleCost, shippingType); output(candleCost, shippingCost); } public static double getCandlecost() { boolean done = false; do{ try { System.out.print("Enter the cost of the candle order "); double candleCost = sc.nextDouble(); done = true; return candleCost; } catch (InputMismatchException e) { System.out.println("Error, Enter a dollar amount greater than 0"); } } while (!done); return 0; } public static int getShippingType() { System.out.println("Enter the type of shipping: "); System.out.println("1> Priority <overnight>"); System.out.println("2> Express <2 business days>"); System.out.println("3> Standard <3 to 7 business days>"); System.out.println("Enter type number: "); int shippingType = sc.nextInt(); if(shippingType == 1){} else if(shippingType == 2){} else if(shippingType == 3){} return shippingType; } public static double getShippingCost(double candleCost, int shippingType) { switch(shippingType) { case 1: candleCost = 16.95 + candleCost; break; case 2: candleCost = 13.95 + candleCost; break; case 3: if (candleCost > 100.00){ candleCost = candleCost; } else{ candleCost = 7.95 + candleCost; } break; } return candleCost; } public static void output(double candleCost, double shippingCost) { DecimalFormat twoDigits = new DecimalFormat("$#,000.00"); System.out.println("The candle cost of " + twoDigits.format(candleCost) + " with shipping costs of " + shippingCost + " equals " + twoDigits.format(candleCost + shippingCost)); } } 。例如,使用GNU Prolog:

write_canonical/1

关于记忆中的表现,我推荐Richard O'Keefe的书。系统之间的细节不同,但您可以非常确定在内存中表示术语| ?- write_canonical([1,2,3]). '.'(1,'.'(2,'.'(3,[]))) ,您需要:

  • functor / arity的一个内存单元
  • 3个参数的存储单元

对于直接内存表示中的术语row(1,2,3),您需要:

  • 三个.(1, .(2, .(3, [])仿函数的3个存储单元
  • 3个存储单元1,2,3
  • 可能还有一些(例如'.'/2)。

从这开始,您已经看到使用列表在此表示中至少大致两次内存。

您可以自己执行的一些简单测试将帮助您查看系统中这些表示的内存消耗差异。

答案 1 :(得分:6)

Something that the other (excellent) answer did not mention:

Access to the member of a list by its position means that you need to traverse the list. Access to the argument of a term should be possible in constant time. So for random access a term should be more efficient.


Short aside: you can attempt to make the list traversal marginally faster. But the SWI-Prolog implementation of nth0_det/3 almost smells of desperation ;)


You might be interested in this thread, esp. this summary that talks about lists and terms among other things.

A few rules of thumb follow.

Use case:

  • if you know in advance how many things you have, use a term.
  • if you can have 0 or more of the same things, use a list.
  • if you need a look-up table, neither is optimal

Efficiency:

  • if you want random access, use a term
  • if your algorithm works well on a singly-linked list, a Prolog list is perfectly good choice.

From the last point follows: try to find algorithms that use linked lists, not random-access arrays. It is not always possible, but for many problems you have a choice. The classical example would be a quick sort vs. a merge sort: in Prolog, a merge sort is definitely quicker.

Either way, first make sure you get it right, then worry about efficiency. And make sure you measure the performance bottlenecks before starting to optimize.

Choosing an optimal algorithm and data structure means, of course, that you need to know both your problem and the available tools. Not relevant to your problem, but the beauty of what used to be the "Standard Template Library" for C++ is that for both algorithms and data structures, time complexity ("big O notation") is an inherent property, not an implementation detail.

答案 2 :(得分:4)

Another aspect is time performance when accessing a specific element. With a list, you get linear access to its elements. But with a compound term of the form functor(arg1, arg2, ..., argn, ...), we can use the standard arg/3 built-in predicate for constant access to any argument. I.e. O(N) versus O(1) with any sensible Prolog implementation.

But there's no definitive answer to your question as formulated. The best solution depends on the particular problem you're solving. For example, applying an operation to all arguments may be faster with a list (compared with using a solution based on arg/3). But it will also depend on the used Prolog system. If performance is a main concern, benchmarking is key. Just avoid doing it at a micro-level and instead take into account how the term is created and accessed in all parts of your application that deal with it.