我一直在尝试学习 Prolog,这个特殊的事情已经困扰我一段时间了:为了完成任何事情,我的查询需要长得惊人。特别是,我有以下代表简单分类程序的片段:
% Define the objects
object(pencil, stationery).
object(apple, organic).
object(eraser, stationery).
object(book, stationery).
object(mouse, electronic).
object(mp3, electronic).
object(ipad, electronic).
% Define the baskets
basket(red_basket, electronic).
basket(tall_basket, stationery).
basket(round_basket, organic).
% Define the sorting rule
sort_object(Object, Basket) :-
object(Object, Type),
basket(Basket, Type).
% Query the program to sort the objects into the baskets
% How can we reduce this last statement to be MUCH shorter?
?- sort_object(pencil, Basket1), sort_object(apple, Basket2), sort_object(eraser, Basket3), sort_object(book, Basket4), sort_object(mouse, Basket5), sort_object(mp3, Basket6), sort_object(ipad, Basket7).
我喜欢所有术语定义都尽可能简洁,但最终的查询对我来说太长了,感觉不对。相反,如果我们要在 Elixir 中实现同样的事情,人们可能会这样做:
defmodule DB do
def objects do
[:pencil, :iPad, :basketball, :laptop, :apple]
end
end
defmodule ObjectHelper do
def get_type(:pencil), do: :stationery
def get_type(:iPad), do: :electronics
def get_type(:basketball), do: :sport
def get_type(:laptop), do: :electronics
def get_type(:apple), do: :food
end
defmodule BasketHelper do
def get_basket(:electronics), do: :red
def get_basket(:stationery), do: :yellow
def get_basket(_), do: :blue
end
DB.objects
|> Enum.group_by(fn o -> o |> ObjectHelper.get_type |> BasketHelper.get_basket end)
|> IO.inspect
目标是为每个对象输出正确的篮子,您可以想象在 C++ 或 Python 中轻松干净地完成此操作,尽管代码较长。
我的问题是:
我正在使用 SWI Prolog。
谢谢!
首先,将
sort_object
重命名为基于关系的名称,而不是操作名称,因为更适合这种双向查找(特别是因为不涉及 sort):
object_basket(Object, Basket) :-
object(Object, Type),
basket(Basket, Type).
然后,可以使用maplist:
?- Objects = [pencil, apple, eraser, book, mouse, mp3, ipad],
maplist(object_basket, Objects, Baskets).
Objects = [pencil, apple, eraser, book, mouse, mp3, ipad],
Baskets = [tall_basket, round_basket, tall_basket, tall_basket, red_basket, red_basket, red_basket].