所以,我正在深入探讨Clojure.Spec.
我偶然发现的一件事是,在哪里提出我的规格.我看到三个选择:
在大多数示例中,我发现在线,有一个大spec.clj文件,在主命名空间中需要.它具有所有(s/def),并(s/fdef)为所有的"数据类型"和功能.
优点:
魂斗罗:
你可以把你(s/def)和(s/fdef)旁边你的产品代码.这样,实现和规范共存于同一个命名空间中.
优点:
魂斗罗:
然后我想,也许Specs是第三种代码(在生产和测试之后).所以也许他们应该拥有自己的命名空间结构,如下所示:
?? src
? ?? package
? ?? a.clj
? ?? b.clj
?? test
? ?? package
? ?? a_test.clj
? ?? b_test.clj
?? spec
?? package
?? a_spec.clj
?? b_spec.clj
Run Code Online (Sandbox Code Playgroud)
优点:
魂斗罗:
谁有使用其中一种方法的经验?
还有其他选择吗?
您如何看待不同的选择?
本clojure.spec指南中的一个示例是一个简单的选项解析规范:
(require '[clojure.spec :as s])
(s/def ::config
(s/* (s/cat :prop string?
:val (s/alt :s string? :b boolean?))))
(s/conform ::config ["-server" "foo" "-verbose" true "-user" "joe"])
;;=> [{:prop "-server", :val [:s "foo"]}
;; {:prop "-verbose", :val [:b true]}
;; {:prop "-user", :val [:s "joe"]}]
Run Code Online (Sandbox Code Playgroud)
稍后,在验证部分中,定义了一个函数,该函数conform使用此规范在内部输入:
(defn- set-config [prop val]
(println "set" prop val))
(defn configure [input]
(let [parsed (s/conform ::config input)]
(if (= parsed ::s/invalid)
(throw (ex-info "Invalid input" (s/explain-data ::config input)))
(doseq [{prop …Run Code Online (Sandbox Code Playgroud) namespaces clojure destructuring cyclic-dependency clojure.spec
在Clojure的类型机制的文档中,有人说
- 具体推导是坏事
- 你不能从具体类,只有接口派生数据类型
但是,一些核心Clojure类使用具体派生(还有其他示例,但这些是超类属于其中的唯一情况clojure.lang):
ARef 扩展 AReferenceAgent 扩展 ARefAtom 扩展 ARefNamespace 扩展 AReferenceRef 扩展 ARefVar 扩展 ARef另外,还有很多抽象类.但是,没有办法在Clojure中创建一个抽象类的等价物,对我来说,抽象类的扩展似乎具有与常规具体派生相同的缺点.
为什么在这里使用具体的推导?
我经常发现自己处在一种情况,我真的不在乎我是否有矢量或地图:
[:foo :bar :baz :qux]
{0 :foo, 1 :bar, 2 :baz, 3 :qux}
Run Code Online (Sandbox Code Playgroud)
重要的功能(get,assoc等)同时适用于两者.有些dissoc人不喜欢向量,但他们有充分的理由不这样做.
但是,我根本不明白为什么keys并且vals在地图上工作而不是向量.有没有什么好的理由可以解释为什么它们没有像这样实现(或者更优雅的多态解决方案)呢?
(defn keys [m]
(if (vector? m)
(seq (range (count m)))
(clojure.lang.RT/keys m)))
(defn vals [m]
(if (vector? m)
(seq m)
(clojure.lang.RT/vals m)))
Run Code Online (Sandbox Code Playgroud)
如果没有充分的理由,我怎样才能尝试在标准Clojure中实现?
写完这个答案之后,我受到启发,尝试使用以下方法指定Clojure的解构语言spec:
(require '[clojure.spec :as s])
(s/def ::binding (s/or :sym ::sym :assoc ::assoc :seq ::seq))
(s/def ::sym (s/and simple-symbol? (complement #{'&})))
Run Code Online (Sandbox Code Playgroud)
顺序解构部分很容易用正则表达式进行规范(所以我在这里忽略它),但我陷入了联想解构.最基本的情况是从绑定表单到键表达式的映射:
(s/def ::mappings (s/map-of ::binding ::s/any :conform-keys true))
Run Code Online (Sandbox Code Playgroud)
但Clojure也提供了几个特殊键:
(s/def ::as ::sym)
(s/def ::or ::mappings)
(s/def ::ident-vec (s/coll-of ident? :kind vector?))
(s/def ::keys ::ident-vec)
(s/def ::strs ::ident-vec)
(s/def ::syms ::ident-vec)
(s/def ::opts (s/keys :opt-un [::as ::or ::keys ::strs ::syms]))
Run Code Online (Sandbox Code Playgroud)
如何::assoc为可以通过将符合::mappings的地图和符合的地图合并在一起创建的地图创建规范::opts?我知道有merge:
(s/def ::assoc (s/merge ::opts ::mappings))
Run Code Online (Sandbox Code Playgroud)
但这不起作用,因为merge …
我的JSP上有一个生成的表,其中包含事务数据:每个单独的事务都是一行,并且有一个类,数量,类型和描述的列.
<table class="table table-striped" id="res">
<tr>
<th>Category</th>
<th>Amount</th>
<th>Type</th>
<th>Description</th>
</tr>
<c:forEach var="element" items="${sessionScope.pick}">
<tr>
<td><c:out value="${element.category}" /></td>
<td class="countable">
<fmt:formatNumber type="currency" currencyCode="USD"
value="${element.amount}"></fmt:formatNumber>
</td>
<td><c:out value="${element.entry_Type}" /></td>
<td><c:out value="${element.description}" /></td>
</tr>
</c:forEach>
</table>
Run Code Online (Sandbox Code Playgroud)
所以它出来了
Category____Amount____Type____Description
我的表使用Struts填充:我在另一个JSP上选择一个部门,然后按"显示"转发到生成表的页面.因此,该表不一定具有设定的行数.我要做的是从每个事务中添加Amount列,这样我就可以显示总数.我尝试使用Javascript做到这一点,但它不适合我:
<script src="http://code.jquery.com/jquery-2.1.4.min.js">
var cls = document.getElementById("res").getElementsByTagName("td");
var sum = 0;
for (var i = 0; i < cls.length; i++){
if(tds[i].className == "countable"){
sum += isNaN(cls[i].innerHTML) ? 0 : parseInt(cls[i].innerHTML);
}
}
document.getElementById("res").innerHTML.append("<tr><td> Total Balance </td><td>" + sum + "</td><td></td><td></td></tr>");
</script>
Run Code Online (Sandbox Code Playgroud)
任何人都可以看到我搞砸了哪里,或者更好的选择是什么?另外,有没有办法对列进行求和并显示总数而不向表中添加另一行?如果可能的话,这将是理想的.
在Clojure中,为什么是do一个特殊的形式,而不是像这样实现的功能?
(defn do [& exprs]
(last exprs))
Run Code Online (Sandbox Code Playgroud) 多行功能或协议文档字符串可以轻松格式化:
(defn foo
"Does a very complicated thing that I need to explain in excruciating detail.
Firstly, this function stringifies x with the standard greeting of 'Hello'.
Secondly, it appends the necessary exclamation point to the resulting string.
Finally, it prints the resulting result to *out*, followed by a newline and
the appropriate flush."
[x]
(println (str "Hello, " x "!")))
(defprotocol Bar
"A retail business establishment that serves alcoholic beverages, such as
beer, wine, liquor, cocktails, and other beverages …Run Code Online (Sandbox Code Playgroud) 假设我有这样的类型:
data Foo = Bar String | Baz | Qux String
Run Code Online (Sandbox Code Playgroud)
我希望有这样的功能:
get : Foo -> String
get (Bar s) = s
get (Qux s) = s
Run Code Online (Sandbox Code Playgroud)
正如所写,这是编译,但并不是全部,因为有缺失的案例; 换句话说,get Baz被视为一个洞而不是一个没有做出类型检查的表达.
我想用Foo类型签名替换它get,指定值必须是a Bar或a Qux.我该如何表达这种Foo类型的子集?
《操作系统概念要点》第 2 版第2.7.5 节(第 83 页)指出(强调原文):
Windows 在很大程度上也是单一的(同样主要是出于性能原因),但它保留了微内核系统的一些典型行为,包括为作为用户模式进程运行的单独子系统(称为操作系统个性)提供支持。
谷歌搜索发现了一堆不相关的在线测验,还有这个维基百科页面,它多次提到这个术语,但似乎没有给出定义。这是标准术语吗?它与其他类似术语(例如上述引用中的“子系统”)的区别是什么?
clojure ×7
clojure.spec ×3
docstring ×1
format ×1
function ×1
idris ×1
inheritance ×1
javascript ×1
jsp ×1
kernel ×1
namespaces ×1
special-form ×1
vector ×1