小编Ral*_*lph的帖子

尾调用优化失败时的Clojure警告/错误

在Scala 2.8.x中,添加了一个新的注释(@tailrec),如果编译器无法对带注释的方法执行尾调用优化,则会产生编译时错误.

在Clojure中是否有类似的设施loop/recur

编辑: 在阅读我的问题的第一个答案(谢谢,Bozhidar Batsov)并进一步搜索Clojure文档后,我发现了这个问题:

(recur exprs*)
按顺序计算exprs,然后并行地将递归点的绑定重新绑定到exprs的值.如果递归点是fn方法,那么它会重新引导params.如果递归点是一个循环,那么它会重新绑定循环绑定.执行然后跳回到递归点.recur表达式必须与递归点的arity完全匹配.特别是,如果递归点是可变参数fn方法的顶部,则不会收集休息参数 - 应该传递单个seq(或null).在尾部位置以外重复是一个错误.

请注意,recur是Clojure中唯一不占用堆栈的循环结构.没有尾调用优化,并且不鼓励使用自调用来循环未知边界.recur是功能性的,它在尾部位置的使用由编译器验证 [强调是我的].

(def factorial
  (fn [n]
    (loop [cnt n acc 1]
       (if (zero? cnt)
            acc
          (recur (dec cnt) (* acc cnt))))))
Run Code Online (Sandbox Code Playgroud)

tail-recursion clojure

9
推荐指数
2
解决办法
678
查看次数

在运行时设置Clojure"常量"

我有一个Clojure程序,我使用Maven构建为JAR文件.嵌入在JAR Manifest中的是构建版本号,包括构建时间戳.

我可以使用以下代码在运行时从JAR Manifest轻松读取:

(defn set-version
  "Set the version variable to the build number."
  []
  (def version
    (-> (str "jar:" (-> my.ns.name (.getProtectionDomain)
                                   (.getCodeSource)
                                   (.getLocation))
                    "!/META-INF/MANIFEST.MF")
      (URL.)
      (.openStream)
      (Manifest.)
      (.. getMainAttributes)
      (.getValue "Build-number"))))
Run Code Online (Sandbox Code Playgroud)

但我被告知def在内部使用是不好的业力defn.

什么是在运行时设置常量的Clojure-idiomatic方法?我显然没有将构建版本信息嵌入到我的代码中def,但我希望它main在程序启动时从函数中设置一次(并且为所有).然后它应该作为def其余运行代码的可用.

更新:BTW,Clojure必须是我在很长一段时间内遇到的最酷的语言之一.感谢Rich Hickey!

runtime constants clojure

9
推荐指数
1
解决办法
1216
查看次数

Clojure中的数据库函数式编程

"如果你拥有的唯一工具是锤子,那就很诱人,把所有东西看作是钉子." - 亚伯拉罕·马斯洛

我需要编写一个工具来将大型分层(SQL)数据库转储到XML.该层次结构由一个的Person与子公司表Address,Phone等表.

  • 我必须转储数千行,所以我想逐步这样做,而不是将整个XML文件保存在内存中.

  • 我想将非纯函数代码隔离到应用程序的一小部分.

  • 我认为这可能是在Clojure中探索FP和并发性的好机会.我还可以向持怀疑态度的同事展示不可变数据和多核利用的好处.

我不确定应用程序的整体架构应该如何.我想我可以使用一个不纯的函数来检索数据库行并返回一个惰性序列,然后可以由返回XML片段的纯函数处理.

对于每一Person行,我可以创建一个Future并且有几个并行处理(输出顺序无关紧要).

当每个Person被处理时,任务将从检索适当的行Address,Phone等等表和生成嵌套XML.

我可以使用通用函数来处理大多数表,依靠数据库元数据来获取列信息,并为需要自定义处理的少数表提供特殊功能.这些功能可以列在一个map(table name -> function).

我是否以正确的方式解决这个问题?我可以轻松地使用Java在OO中执行此操作,但这并不好玩.

顺便说一句,有没有关于FP模式或架构的好书?我有几本关于Clojure,Scala和F#的好书,虽然每个都很好地涵盖了语言,但没有人看过功能编程设计的"大图".

database functional-programming clojure

9
推荐指数
1
解决办法
1049
查看次数

Clojure defprotocol作为表达问题的解决方案

在"Clojure的喜悦"一书中,defprotocol提供了表达式问题的解决方案- "希望为现有的具体类实现一组现有的抽象方法,而不必更改定义任何一个的代码."

给出的例子如下:

(defprotocol Concatenatable
  (cat [this other]))

(extend-type String
  Concatenatable
  (cat [this other]
    (.concat this other)))

(cat "House" " of Leaves")
;=> "House of Leaves"

(extend-type java.util.List
  Concatenatable
  (cat [this other]
    (concat this other)))

(cat [1 2 3] [4 5 6])
;=> (1 2 3 4 5 6)
Run Code Online (Sandbox Code Playgroud)

有人认为这在Java这样的语言中是不可能的,但它与以下内容有何不同?

public class Util {
  public static String cat(final String first,
                           final String second) {
    return first.concat(second);
  }

  public static <T> List<T> cat(final List<T> first,
                                final List<T> …
Run Code Online (Sandbox Code Playgroud)

polymorphism clojure

9
推荐指数
1
解决办法
1811
查看次数

在Scala中重复列表

我是Scala noob.我决定写一个蜘蛛纸牌解算器作为第一个练习,以学习语言和函数式编程.

我想生成一个包含1,2或4套西装的随机洗牌.这是我想出的:

val numberOfSuits = 1
(List("clubs", "diamonds", "hearts", "spades").take(numberOfSuits) * 4).take(4)
Run Code Online (Sandbox Code Playgroud)

应该返回

List("clubs", "clubs", "clubs", "clubs")
List("clubs", "diamonds", "clubs", "diamonds")
List("clubs", "diamonds", "hearts", "spades")
Run Code Online (Sandbox Code Playgroud)

取决于numberOfSuits的值,除了没有我可以找到的List"multiply"操作.我错过了吗?在洗牌之前是否有更好的方法来生成完整的牌组?

顺便说一句,我打算在套装中使用Enumeration,但用字符串输入我的问题更容易.我将采用上面生成的列表并使用for comprehension,迭代套装和类似的卡片"排名"列表以生成完整的套牌.

scala

8
推荐指数
3
解决办法
1万
查看次数

测试Maven中的Clojure

我是Maven的新人,甚至是Clojure的新人.作为学习语言的练习,我正在写一个蜘蛛纸牌播放器程序.我还计划在Scala中编写类似的程序来比较实现(请参阅我的帖子/sf/ask/179988721/).

我已经配置了一个包含通常的src/main/clojure和src/test/clojure目录的Maven目录结构.我的pom.xml文件包含clojure-maven-plugin.当我运行"mvn test"时,它显示"没有运行测试",尽管我在src/test/clojure目录中有测试代码.当我误解了什么?这是我的pom.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>SpiderPlayer</groupId>
    <artifactId>SpiderPlayer</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <inceptionYear>2010</inceptionYear>

    <packaging>jar</packaging>

    <properties>
        <maven.build.timestamp.format>yyMMdd.HHmm</maven.build.timestamp.format>
        <main.dir>org/dogdaze/spider_player</main.dir>
        <main.package>org.dogdaze.spider_player</main.package>
        <main.class>${main.package}.Main</main.class>
    </properties>

    <build>
        <sourceDirectory>src/main/clojure</sourceDirectory>
        <testSourceDirectory>src/test/clojure</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>com.theoryinpractise</groupId>
                <artifactId>clojure-maven-plugin</artifactId>
                <version>1.3.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <phase>generate-sources</phase>
                        <configuration>
                            <tasks>
                                <echo file="${project.build.sourceDirectory}/${main.dir}/Version.clj"
                                      message="(ns ${main.package})${line.separator}"/>
                                <echo file="${project.build.sourceDirectory}/${main.dir}/Version.clj" append="true"
                                      message="(def version &quot;${maven.build.timestamp}&quot;)${line.separator}"/>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                            <archive>
                                <manifest>
                                    <mainClass>${main.class}</mainClass>
                                </manifest>
                            </archive> …
Run Code Online (Sandbox Code Playgroud)

java maven-2 unit-testing clojure

8
推荐指数
1
解决办法
2495
查看次数

Clojure宏扩展

为什么

(macroexpand '(.. arm getHand getFinger))
Run Code Online (Sandbox Code Playgroud)

扩展到

(. (. arm getHand) getFinger)
Run Code Online (Sandbox Code Playgroud)

(macroexpand '(-> arm getHand getFinger))
Run Code Online (Sandbox Code Playgroud)

扩展到

(getFinger (clojure.core/-> arm getHand))
Run Code Online (Sandbox Code Playgroud)

换句话说,为什么->第二个例子没有完全扩展呢?

macros clojure

8
推荐指数
1
解决办法
1610
查看次数

从clojure宏返回多个值

我需要为Clojure添加几个方法defprotocol,我正在为几个相同的Swing组件编写:

(defprotocol view-methods
  (ok-button-add-action-listener     [this listener])
  (ok-button-set-enabled             [this enabled])
  (ok-button-set-selected            [this selected])
  (cancel-button-add-action-listener [this listener])
  (cancel-button-set-enabled         [this enabled])
  (cancel-button-set-selected        [this selected])
  (other-button-add-action-listener  [this listener])
  (other-button-set-enabled          [this enabled])
  (other-button-set-selected         [this selected]))
Run Code Online (Sandbox Code Playgroud)

有没有办法,我可以写一个宏,返回所有三个方法签名(任何方式xxx-button-add-action-listener,xxx-button-set-enabled,xxx-button-set-selected)?

(defprotocol view-methods
  (add-methods ok)
  (add-methods cancel)
  (add-methods other))
Run Code Online (Sandbox Code Playgroud)

这个宏需要在defprotocol每次调用时增加三个项目.

一个宏可以返回`~@a-list并扩展"到位"吗?

macros clojure

8
推荐指数
1
解决办法
1123
查看次数

Clojure"DSL"编程

我正在使用Clojure和RESTEasy设计JAX-RS REST服务器.

我的理解是,用Lisp族语言编写的应用程序比"传统"命令式语言中的应用程序更多地构建为"特定于域的语言".应用程序从下到上设计为越来越"精致"的功能,直到"顶层"应用程序成为对高级功能的一系列函数调用.

我试图为我的REST服务器执行此操作,从服务URL请求的资源类开始(GET,POST,PUT,DELETE).

这是我的第一个资源:

(ns com.example.server.resources.buildtime
  (:import [javax.ws.rs CookieParam GET Produces Path]
           [javax.ws.rs.core Context Cookie NewCookie Response UriInfo]
           [org.jboss.resteasy.annotations.providers.jaxb Formatted]))

(definterface BuildTime
  (getBuildTime [^javax.ws.rs.core.UriInfo info
                 ^javax.ws.rs.core.Cookie security-cookie]))

(deftype
  ^{Formatted true}
  BuildTimeResource []
  BuildTime
  (^{GET true
     Path "/buildtime"
     Produces ["application/json"]}
    getBuildTime
    [this info security-cookie]
    (.. (Response/ok "20111009") build)))
Run Code Online (Sandbox Code Playgroud)

当使用GET http方法在URL"/ buildtime"调用时,此资源将服务器构建时间作为String(包含在JSON包中)返回.

我将编写更多这些资源类和封闭方法(大多数类将有多个方法),每个都有一个definterface和一个deftype.这似乎是宏的完美用法.

我正在征求关于如何以DSL方式完成这项工作的建议.如何根据DSL进行思考?

dsl clojure

8
推荐指数
1
解决办法
1381
查看次数

在Datomic中查找缺少属性的实体

如果我有以下Datomic数据库:

{ :fred :age 42 }
{ :fred :likes :pizza }
{ :sally :age 42 }
Run Code Online (Sandbox Code Playgroud)

如何查询两个实体(:fred:sally),取回属性:likes :pizza:fred和一个空值:sally

查询

[:find ?n ?a ?l
 :where [?n :age ?a]
        [?n :likes ?l]]
Run Code Online (Sandbox Code Playgroud)

只返回:fred 42 :pizza.

missing-data datomic

8
推荐指数
3
解决办法
2524
查看次数