如果传递了这样的对列表,我有一个谓词,这是真的,例如:
translatable([(dog,perro)], [(perro,hund)], [(dog,hund)])
意味着 - 如果" dog"转换为" perro"和" perro"转换为" hund"然后确实" dog"转换为" hund"。
以下是完整代码。返回/建议对的第一个成员 - 给定((a,b),a)返回true,给定((a,b),X)返回X = a:
first((First, _), First).
类似于"第一个",但是对于第二对成员:
second((_, Second), Second).
如果元组列表中存在可翻译单词,则返回true,并将翻译保存到翻译:( dog,Translation,[(bed,cama),(dog,perro)]
translation_exists(Word, Translation, [H|T]) :-
first(H, Word), second(H, Translation), !;
translation_exists(Word, Translation, T).
结果:
translatable(EnglishSpanish, SpanishGerman, EnglishGerman) :-
forall(member(Pair, EnglishGerman), (
first(Pair, Word),
second(Pair, ResultTranslation),
translation_exists(Word, Translation, EnglishSpanish),
translation_exists(Translation, ResultTranslation, SpanishGerman)
)).
此代码正确返回true / false。 但是,为什么,给定 可翻译的([(dog,perro)],[(perro,hund)],X)。
它不会返回X = [(dog,hund)]?
修改的 更具体地说,实际目标是: 找出LAST字典是否具有可翻译对(仅限它们)。 Daniel,非常感谢,我已经采纳了你建议的会员功能 - 很简单,谢谢!这就是我现在的所有代码:
lastIsTranslatable(_, _, []).
lastIsTranslatable(EngSpan, SpanGerm, [(Eng, Germ) | T]) :-
member((Eng, Span), EngSpan),
member((Span, Germ), SpanGerm),
% this is to protect endless [(dog,hund), (dog, hund), ...]
not(member((Eng, Germ), T)),
lastIsTranslatable(EngSpan, SpanGerm, T),
!.
然而,这很有用,发现真正的&题:
lastIsTranslatable([(a,b)], [(b,c)], [(a,c)]).
lastIsTranslatable([(a,b)], [(b,c)], [(a,no)]).
但是
lastIsTranslatable([(a,b)], [(b,c)], X).
结果是X = [],然后,在击中";" - 假。为什么? 好吧,使用跟踪选项运行,我看到执行失败
not(member((Eng, Germ), T))
但是否则产生的X将无休止地填充(a,c),(a,c)...也许有更好的方法来防止重复?
答案 0 :(得分:1)
原因,基本上是因为EnglishGerman
未经实例化,member/2
可以自由地为其提供可能的列表:
?- member((perro,X), List).
member((perro,X), List).
List = [ (perro, X)|_G18493911] ;
List = [_G18493910, (perro, X)|_G18493914] ;
List = [_G18493910, _G18493913, (perro, X)|_G18493917] ;
List = [_G18493910, _G18493913, _G18493916, (perro, X)|_G18493920]
...
这是最直接的问题,但即使您更改了数据流,我认为您仍会遇到问题:
translatable1(EnglishSpanish, SpanishGerman, EnglishGerman) :-
member((English,Spanish), EnglishSpanish),
member((Spanish,German), SpanishGerman),
member((English,German), EnglishGerman).
请注意,我放弃了first/2
和second/2
谓词,转而支持模式匹配;我认为这更清楚。
除了:如果您知道自己的列表是具体的,并且不想生成多个解决方案,则可以使用
memberchk/2
来验证元素是否存在而不是{{ 1}};它更便宜,更具决定性。
这样做效果更好(无论如何都可以获得解决方案),但仍然可以获得比您需要的更多解决方案:
member/2
我们知道我们的代码不知道的是结果集的基数应该小于或等于我们输入的最低基数;如果我有15个英语 - 西班牙语单词和12个西班牙语 - 德语单词,我的英语 - 德语结果中不能超过12个单词。我们的代码不知道的原因是因为它试图表现得像数学:我们的代码基本上是说"对于英语 - 西班牙语的每个元素,如果存在匹配的西班牙语 - 德语元素,那么也是英语 - 德语的一个元素。"这并没有告诉我们如何构建英语 - 德语!它只告诉我们一个关于英语 - 德语的事实,我们可以用英语 - 西班牙语和西班牙语 - 德语进行验证!所以它很酷,但它还不足以计算英语 - 德语。
除了:在Prolog中常规使用
?- translatable1([(dog,perro)], [(perro,hund)], X). X = [ (dog, hund)|_G18493925] ; X = [_G18493924, (dog, hund)|_G18493928] ; X = [_G18493924, _G18493927, (dog, hund)|_G18493931] a
代替a-b
;你很容易让自己相信Prolog在没有元组的情况下会产生元组,并且运算符的优先级会让人感到困惑。
那么,我们如何告诉Prolog如何计算英语 - 德语?可能有很多种方法,但我更愿意使用(a,b)
,因为我们的设定基数约束(以及它将会收敛/停止的一般意义)将自然地从计算中出现"用完了&# 34;输入设置就好了。
select/3
基础案件应该是显而易见的;如果我们没有英语 - 西班牙语或西班牙语 - 德语,那么还有什么可以计算的。然后归纳案例剥离英语 - 西班牙语列表中的第一项并搜索匹配的西班牙语 - 德语翻译。如果找到一个,它会用它来构建结果;否则,它只会在剩余的英语 - 西班牙语列表中重复出现。这样,在每次迭代时,我们至少会从该列表中删除英语 - 西班牙语翻译,并且我们会在使用时丢弃西班牙语 - 德语翻译。所以看起来直觉上很可能会在没有产生一堆额外选择点的情况下工作和终止。
似乎可以解决这个问题:
translatable2([], _, []).
translatable2(_, [], []).
translatable2([Eng-Span|EngSpanRem], SpanGerm, EngGerm) :-
(select(Span-Germ, SpanGerm, SpanGermRem) ->
translatable2(EngSpanRem, SpanGermRem, EngGermRem),
EngGerm = [Eng-Germ|EngGermRem]
;
translatable2(EngSpanRem, SpanGerm, EngGerm)
).
这是额外的结果,因为我们击中了两个终端案例,因为两个列表都成为?- translatable2([dog-perro], [perro-hund], X).
X = [dog-hund] ;
X = [dog-hund].
;这并不吸引人,但也不用担心任何事情。
现在有一件事对于这个解决方案很糟糕,它将前两个参数视为参数,最后一个参数作为参数,你真的无法做到这一点。我不知道这对你来说是否是一个问题; []
不应该有这个限制,但因为translatable/1
发生在member((Spanish,German), SpanishGerman)
之前,它最终会生成一个无限大的列表,因此会搜索缺少的西班牙语 - 德语翻译。
但是,只要你提供任何两个这样的输入,感觉应该有可能提出一个通用的谓词。如果我知道所有三个列表都是完整的并且顺序相同,我就可以这样做:
member((English,German), EnglishGerman)
你可以看到它的工作原理如下:
translatable3([], [], []).
translatable3([X-Y|XYs], [Y-Z|YZs], [X-Z|XZs]) :-
translatable3(XYs, YZs, XZs).
但我对你的约束知之甚少,不知道这是否是合法的答案。我的怀疑是否定的,因为语言不会这样,但谁知道?
无论如何,这是三种不同的方法;我希望其中一个对你有所帮助!