Clojure 如何在core.logic中分解映射?

Clojure 如何在core.logic中分解映射?,clojure,clojure-core.logic,Clojure,Clojure Core.logic,我相信在core.logic中解构映射时遇到问题。我有以下代码: ... used clojure.core.logic ... required clojure.core.logic.arithmetic as logic.arithmetic. (def hand ({:rank 9, :suit :hearts} {:rank 13, :suit :clubs} {:rank 6, :suit :spades}

我相信在core.logic中解构映射时遇到问题。我有以下代码:

... used clojure.core.logic 
... required clojure.core.logic.arithmetic as logic.arithmetic. 

(def hand ({:rank 9, :suit :hearts} 
           {:rank 13, :suit :clubs} 
           {:rank 6, :suit :spades} 
           {:rank 8, :suit :hearts} 
           {:rank 12, :suit :clubs}))

(run* [q]
  (fresh [v w x y z]  ;;cards
    (== q [v w x y z])
    (membero v hand)
    (membero w hand)
    (membero x hand)
    (membero y hand)
    (membero z hand)
    (fresh [a b c d e]  ;;ranks
      (== {:rank a} v)
      (== {:rank b} w)
      (== {:rank c} x)
      (== {:rank d} y)
      (== {:rank e} z)
      (logic.arithmetic/>= a b)
      (logic.arithmetic/>= b c)
      (logic.arithmetic/>= c d)
      (logic.arithmetic/>= d e))
    (distincto q)))

它返回空列表(),表示未找到匹配项。我认为这是代码(={:rank a}v)部分的一个问题。我试图简单地返回q,其中q是一个按:降序排列的映射向量。

显然,您必须在映射上进行精确匹配。这意味着您可以创建垃圾变量来捕获您不感兴趣的任何内容的值。看起来很奇怪,但还好

(run* [q]
  (fresh [v w x y z]  ;;cards
    (== q [v w x y z])
    (membero v hand)
    (membero w hand)
    (membero x hand)
    (membero y hand)
    (membero z hand)
    (fresh [a b c d e, f g h i j]  ;;ranks, garbage
      (== {:rank a :suit f } v)
      (== {:rank b :suit g } w)
      (== {:rank c :suit h } x)
      (== {:rank d :suit i } y)
      (== {:rank e :suit j } z)
      (logic.arithmetic/>= a b)
      (logic.arithmetic/>= b c)
      (logic.arithmetic/>= c d)
      (logic.arithmetic/>= d e))
      (distincto q)))
最后,这里是一个更简洁、更快、更混乱的版本

(run* [q]
  (fresh [v w x y z]  ;;cards
    (permuteo hand q)
    (== q [v w x y z])
    (fresh [a b c d e, f g h i j]  ;;ranks, garbage
      (== {:rank a :suit f } v)
      (== {:rank b :suit g } w)
      (logic.arithmetic/>= a b)
      (== {:rank c :suit h } x)
      (logic.arithmetic/>= b c)
      (== {:rank d :suit i } y)
      (logic.arithmetic/>= c d)
      (== {:rank e :suit j } z)
      (logic.arithmetic/>= d e))))

如果不需要引用逻辑变量,则实际上不需要将其命名为:

(== {:rank a :suit (lvar)} v)

我发现自己越来越多地使用
(lvar)
。它通常使代码比一次性使用的变量更清晰,但我真希望有更好的方法来表达这一点。

现在可以使用最新的core.logic 0.8.3版编写更简洁的解决方案:

(ns cards
  (:refer-clojure :exclude [==])
  (:use [clojure.core.logic])
  (:require [clojure.core.logic.fd :as fd]))

(def hand
  [{:rank 9, :suit :hearts} 
   {:rank 13, :suit :clubs} 
   {:rank 6, :suit :spades} 
   {:rank 8, :suit :hearts} 
   {:rank 12, :suit :clubs}])

(defn ranko [card rank]
  (featurec card {:rank rank}))

(run* [v w x y z :as q]
  (permuteo hand q)
  (fresh [a b c d e]
    (ranko v a) (ranko w b) (ranko x c)
    (fd/>= a b) (fd/>= b c)
    (ranko y d) (ranko z e)
    (fd/>= c d) (fd/>= d e)))

现在可以使用
featurec
只匹配地图的一部分。我还建议使用新的有限域名称空间,而不是算术名称空间。