【问题标题】:How do I use core.logic to search for valid nested maps in a database of maps?如何使用 core.logic 在地图数据库中搜索有效的嵌套地图?
【发布时间】:2020-10-06 17:31:50
【问题描述】:

我目前正在处理一个问题,要求寻找可以履行订单的特定供应商。供应商以地图表示,订单也是如此。如果供应商能够提供订单的邮政编码、订单的服务水平、订单请求的车辆,并且具有适当的额外便利条件,则供应商可以履行订单。我一直在尝试使用 core.logic 来解决这个问题,因此我将供应商存储在使用 core.logic.pldb 作为车队的逻辑数据库中。在研究了如何将 core.logic 与 Clojure 映射一起使用之后,我一直在尝试结合使用 featurec、membero 和 PMap 来解决问题。下面显示的代码是我目前的工作状态。

(pldb/db-rel fleet fl)

(def f1 {:id 1
         :zipcodes #{"02138" "33135" "33157" "02139"}
         :services #{"standard" "through_door" "to_curb" "to_door"}
         :vehicles #{"any" "sedan" "suv" "wav"}
         :extra {:covid-19 true}
         :cost 20
         :weight 100})


(def f2 {:id 2
         :zipcodes #{"33157" "02139"}
         :services #{"standard" "through_door"}
         :vehicles #{"sedan" "suv"}
         :extra {:covid-19 true}
         :cost 40
         :weight 80})


(def f3 {:id 3
         :zipcodes #{"02138" "33135"}
         :services #{"to_curb" "to_door"}
         :vehicles #{"any" "sedan"}
         :extra {:covid-19 true}
         :cost 60
         :weight 120})


(def ex_m {:ride {:zipcodes "02138"
                  :appointment-time "0630"
                  :services "to_curb"
                  :vehicles "sedan"}
           :accessibility {:extra {:covid-19 true}}})


(def fleets
  (pldb/db
    [fleet (map->PMap f1)]
    [fleet (map->PMap f2)]
    [fleet (map->PMap f3)]))


 (defn find-fleets [m] 
   (run-db* fleets [fl]
            (fresh [fl_zipcodes fl_services fl_vehicles fl_covid
                    ride_info ride_zip ride_service ride_vehicle ride_covid]
                   (membero ride_zip fl_zipcodes)
                   (membero ride_service fl_services)
                   (membero ride_vehicle fl_vehicles)
                   (== fl_covid ride_covid)
                   (featurec fl {:zipcodes fl_zipcodes
                                 :services fl_services
                                 :vehicles fl_vehicles
                                 :extra {:covid-19 fl_covid}})
                   (featurec m {:ride ride_info
                                :accessibility {:extra {:covid-19 ride_covid}}})
                   (featurec ride_info {:zipcodes ride_zip
                                        :services ride_service
                                        :vehicles ride_vehicle}))))

但是,当我尝试运行上面的 find-fleets 函数时,就像这样,

   (find-fleets (map->PMap ex_m))

我得到以下错误和跟踪:

   ; Error printing return value (StackOverflowError) at clojure.lang.KeywordLookupSite$1/get (KeywordLookupSite.java:45).
   ; null

关于 core.logic 以及如何将它与 Clojure 映射一起使用,我在这里有什么遗漏吗?我只是错过了一些愚蠢的错误吗?

提前谢谢你!

【问题讨论】:

  • 除非您的目标是学习 core.logic,否则我只会使用普通的 filterand,使用 contains? 检查 3 个参数。
  • 恐怕学习core.logic是目标之一,因为我们未来计划开发core.logic功能很重。
  • 您的错误消息听起来像是 core.logic 成功为您找到了一个结果,但该结果在某种程度上是循环的:它包含自身或其他东西。因此,当您尝试打印出无限嵌套的地图/列表时,您会遇到堆栈溢出。您可以尝试不打印结果,而是将其保存到 var 中,以确认此猜测。然后戳它看看它是什么类型,它的键是什么,等等。

标签: clojure clojure-core.logic


【解决方案1】:

如果你稍微重新表述你的问题,你可以从the Tupelo library 解决这个using the submatch? function。来自文档:

(submatch? smaller larger)

  Returns true if the first arg is (recursively) a 
  subset/submap/subvec of the 2nd arg

一个例子

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require [tupelo.core :as t]))

(def shops
  [{:id       1
    :zipcodes #{"02138" "33135" "33157" "02139"}
    :services #{"standard" "through_door" "to_curb" "to_door"}
    :vehicles #{"any" "sedan" "suv" "wav"}
    :extra    {:covid-19 true}
    :cost     20
    :weight   100}

   {:id       2
    :zipcodes #{"33157" "02139"}
    :services #{"standard" "through_door"}
    :vehicles #{"sedan" "suv"}
    :extra    {:covid-19 true}
    :cost     40
    :weight   80}

   {:id       3
    :zipcodes #{"02138" "33135"}
    :services #{"to_curb" "to_door"}
    :vehicles #{"any" "sedan"}
    :extra    {:covid-19 true}
    :cost     60
    :weight   120}])

定义维修作业以匹配商店的结构(具有集合或地图值的地图)。

(def job
  {:zipcodes #{"02138"}
   :services #{"to_curb"}
   :vehicles #{"sedan"}
   :extra    {:covid-19 true}})

单元测试显示submatch? 函数在起作用。

(dotest
  (let [matches (t/keep-if #(t/submatch? job %) shops)]  ; synonym for `filter`
    (is= matches
      [{:id       1,
        :zipcodes #{"02138" "02139" "33157" "33135"},
        :services #{"to_curb" "standard" "to_door" "through_door"},
        :vehicles #{"wav" "any" "suv" "sedan"},
        :extra    {:covid-19 true},
        :cost     20,
        :weight   100}
       {:id       3,
        :zipcodes #{"02138" "33135"},
        :services #{"to_curb" "to_door"},
        :vehicles #{"any" "sedan"},
        :extra    {:covid-19 true},
        :cost     60,
        :weight   120}])
    ))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-22
    • 2012-03-04
    • 2021-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-18
    相关资源
    最近更新 更多