Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >几分钟内学习 Clojure

几分钟内学习 Clojure

作者头像
阳光岛主
发布于 2019-02-19 02:25:40
发布于 2019-02-19 02:25:40
1.8K00
代码可运行
举报
文章被收录于专栏:米扑专栏米扑专栏
运行总次数:0
代码可运行

Clojure 是JVM上的一个LISP语言变种,它比Common Lisp更强调纯函数式编程,但提供了一些STM工具以处理它所引入的状态问题。

Clojure源码托管在:github

在线练习编译环境: himera

learnclojure.clj 示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
; 分号作为注释的开始

; Clojure 用一种把元素用括号括起来的像列表一样的方式来书写,元素之间用空格隔开
; clojure 解释器会把第一个元素当做是函数或者宏调用,其他的都作为参数
; 下面这个函数用于设置当前的命名空间
(ns test)

; 更多基本的例子:

; str 函数会用它所有的参数创造一个字符串
(str "Hello" " " "World") ; => "Hello World"

; 数学运算很直观,不过是前缀表达式
(+ 1 1) ; => 2
(- 2 1) ; => 1
(* 1 2) ; => 2
(/ 2 1) ; => 2

;  相等比较使用 “=”符号
(= 1 1) ; => true
(= 2 1) ; => false

; 你也不必担心逻辑运算
(not true) ; => false

; 嵌套方式正如你预料的那样
(+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2

; 类型系统
;;;;;;;;;;;;;

; Clojure 使用java对象类型来表示 布尔值、字符串和数字
; 使用 `class`函数来检测它们.
(class 1) ; 整形字面值默认是java中的Long类型
(class 1.); 浮点字面值对应着java中的Double类型
(class ""); 字符串总是用双引号括起来,并且对应着java中的Sring类型
(class false) ;布尔值对应着java中的Boolean类型
(class nil); null值被称为 nil(英语含义:无、零点)

; 如果你想创建一列数据字面值, 使用一个单引号 ' 来防表达式被解析执行
'(+ 1 2) ; => (+ 1 2) ;这里没有返回3
; (上面表达式和(quote (+ 1 2)) 等价,不过更简洁

; 你可以运算一个引用列表
(eval '(+ 1 2)) ; => 3

; 集合和序列
;;;;;;;;;;;;;;;;;;;

; 向量和列表也是java类哦!!
(class [1 2 3]); => clojure.lang.PersistentVector
(class '(1 2 3)); => clojure.lang.PersistentList

;书写一个列表形如(1 2 3)一样简单, 但是我们不得不把它“引”(前面加个单引号)起来
;这样就能防止解释器把它当做一个函数来解析
;另外,(list 1 2 3) 和 '(1 2 3) 等价

;列表和向量都是集合:
(coll? '(1 2 3)) ; => true
(coll? [1 2 3]) ; => true

; 只有列表是序列.(序列是有顺序的)
(seq? '(1 2 3)) ; => true
(seq? [1 2 3]) ; => false

; 序列是列表一种逻辑上的接口,可以懒加载.
; "懒" 意味着可以定义无穷序列,就像下面一样:
(range 4) ; => (0 1 2 3)
(range) ; => (0 1 2 3 4 ...) (一个无穷序列)
(take 4 (range)) ;  (0 1 2 3)

; 使用cons 来追加一个元素到列表或者向量的头部
(cons 4 [1 2 3]) ; => (4 1 2 3)
(cons 4 '(1 2 3)) ; => (4 1 2 3)

; 使用conj追加一个元素到列表的头部,或者向量的尾部,
(conj [1 2 3] 4) ; => [1 2 3 4]
(conj '(1 2 3) 4) ; => (4 1 2 3)

; 使用concat来连接列表和向量
(concat [1 2] '(3 4)) ; => (1 2 3 4)

; 使用filter, map 来进行列表计算
(map inc [1 2 3]) ; => (2 3 4)
(filter even? [1 2 3]) ; => (2)

; 使用reduce 来进行化繁为简  (map/reduce 思想就来自于lisp)
(reduce + [1 2 3 4])
; = (+ (+ (+ 1 2) 3) 4)
; => 10

; Reduce 可以使用一个初始值
(reduce conj [] '(3 2 1))
; = (conj (conj (conj [] 3) 2) 1)
; => [3 2 1]

; 函数
;;;;;;;;;;;;;;;;;;;;;

; 使用fn来创建一个函数。所有的函数都有返回值,就是它的最后一个表达式
(fn [] "Hello World") ; => fn

; (你需要额外的括号去调用它)
((fn [] "Hello World")) ; => "Hello World"

;你可以使用def来创建变量
(def x 1)
x ; => 1

; 将函数赋值给一个变量
(def hello-world (fn [] "Hello World"))
(hello-world) ; => "Hello World"

; 你可以使用defn来简化定义过程
(defn hello-world [] "Hello World")

;[] 是函数的参数列表
(defn hello [name]
  (str "Hello " name))
(hello "Steve") ; => "Hello Steve"

; 你也可以使用下面这种简写方式
(def hello2 #(str "Hello " %1))
(hello2 "Fanny") ; => "Hello Fanny"

; 你可以创建拥有可变参数的函数
(defn hello3
  ([] "Hello World")
  ([name] (str "Hello " name)))
(hello3 "Jake") ; => "Hello Jake"
(hello3) ; => "Hello World"

; 函数允许将参数打包成列表 (有点类似python中的*
(defn count-args [& args]
  (str "You passed " (count args) " args: " args))
(count-args 1 2 3) ; => "You passed 3 args: (1 2 3)"

; 你可以将普通参数和列表参数混合使用
(defn hello-count [name & args]
  (str "Hello " name ", you passed " (count args) " extra args"))
(hello-count "Finn" 1 2 3)
; => "Hello Finn, you passed 3 extra args"


; 哈希表
;;;;;;;;;;

(class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap

; 关键字类似字符串,但是做了一些性能上的优化
(class :a) ; => clojure.lang.Keyword

; Maps 的键可以是任意类型,但是通常推荐使用keywords
(def stringmap (hash-map "a" 1, "b" 2, "c" 3))
stringmap  ; => {"a" 1, "b" 2, "c" 3}

(def keymap (hash-map :a 1 :b 2 :c 3))
keymap ; => {:a 1, :c 3, :b 2} (不保证顺序)

; 顺便说一下, 逗号只是为了看着更清晰,其他都和空格一样,什么都不做.

; 从一个map中检索一个值,可以直接把这个map当做函数调用(这个NB
(stringmap "a") ; => 1
(keymap :a) ; => 1

; 关键字也可以当做函数来调用,从一个map中检索值(这个更NB
(:b keymap) ; => 2

; stings 可没有这个功能,所以下面会抛出异常。(这也是为什么推荐使用keywords)
;("a" stringmap)
; => Exception: java.lang.String cannot be cast to clojure.lang.IFn

; 检索一个不存在的值会返回nil
(stringmap "d") ; => nil

; 使用assoc 向一个map中添加新的键值对。
(assoc keymap :d 4) ; => {:a 1, :b 2, :c 3, :d 4}

; 请记住, clojure 类型是不可变的!
keymap ; => {:a 1, :b 2, :c 3}

; 使用dissoc 来删除key(可以删除多个)
(dissoc keymap :a :b) ; => {:c 3}

; 集合
;;;;;;

(class #{1 2 3}) ; => clojure.lang.PersistentHashSet
(set [1 2 3 1 2 3 3 2 1 3 2 1]) ; => #{1 2 3}

; 使用con来添加新值
(conj #{1 2 3} 4) ; => #{1 2 3 4}

; 使用disj删除原有值
(disj #{1 2 3} 1) ; => #{2 3}

; 直接将set当做函数来测试是否包含某个值(NB
(#{1 2 3} 1) ; => 1  (有就返回原有的值)
(#{1 2 3} 4) ; => nil (没有就返回nil)

; clojure.sets 命名空间包含更多的函数

; 一些有用的形式
;;;;;;;;;;;;;;;;;

; clojure中的逻辑结构都是宏, 看起来也没什么不同
(if false "a" "b") ; => "b"
(if false "a") ; => nil

; 使用let 来创建临时绑定
(let [a 1 b 2]
  (> a b)) ; => false

; 执行多条语句,返回最后一条语句
(do
  (print "Hello")
  "World") ; => "World" (prints "Hello")

; 所有的函数都包含一个隐式的do
(defn print-and-say-hello [name]
  (print "Saying hello to " name)
  (str "Hello " name))
(print-and-say-hello "Jeff") ;=> "Hello Jeff" (prints "Saying hello to Jeff")

; let绑定也是哦
(let [name "Urkel"]
  (print "Saying hello to " name)
  (str "Hello " name)) ; => "Hello Urkel" (prints "Saying hello to Urkel")

; 模块
;;;;;;;;;;;;;;;

; 使用“use”来获得一个模块中所有的函数
(use 'clojure.set)

; 现在我们可以使用集合操作
(intersection #{1 2 3} #{2 3 4}) ; => #{2 3}  求交集
(difference #{1 2 3} #{2 3 4}) ; => #{1}   求差集

; 你可以只导入一个函数子集(例如下面只包含交集函数)
(use '[clojure.set :only [intersection]])

; 使用reqire来导入一个模块
(require 'clojure.string)

; 使用/从一个模块中调用函数
(clojure.string/blank? "") ; => true

; 你可以在导入模块的时候自定义名称
(require '[clojure.string :as str])  
(str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst."
; (#"" denotes a regular expression literal)

; 你可以使用":require" 从一个命名空间中引入模块(use也可以,但是别这么做)
; 如果你使用:require的话,就没必要把模块“引”(前面加个单引号)起来了.
(ns test
  (:require
    [clojure.string :as str]
    [clojure.set :as set]))

; Java
;;;;;;;;;;;;;;;;;

; java 拥有一个庞大的各种用途的标准库,你一定迫不及待想学习如何在clojure中使用这些库

; 使用import类引入java模块(这个还好没变化)
(import java.util.Date)

; 你也可以从一个命名空间中引入
(ns test
  (:import java.util.Date
           java.util.Calendar))

; 类名字后加个”."用来创建一个对象
(Date.) ; <a date object>

; 使用. 来调用方法. 或者使用“.方法名"简写的方式
(. (Date.) getTime) ; <a timestamp>
(.getTime (Date.)) ; 和上面一样哦

; 使用/ 来调用静态方法
(System/currentTimeMillis) ; <a timestamp> (system is always present)

; 使用 doto 来处理可变的类<span style="font-family:宋体;">,所有的函数始终用最初的那个对象值,最后还是返回最初的那个对象</span>  (import java.util.Calendar)
(doto (Calendar/getInstance)
  (.set 2000 1 1 0 0 0)
  .getTime) ; => A Date. set to 2000-01-01 00:00:00

参考推荐:

clojure.org

ClojureScript REPL

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2013年11月18日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Clojure Web 开发-- Ring 使用指南
在 Clojure 众多的 Web 框架中,Ring 以其简单统一的 HTTP 抽象模型脱颖而出。Ring 充分体现了函数式编程的思想——通过一系列函数的组合形成了一个易于理解、扩展的 HTTP 处理链。
飞驰的西瓜
2022/07/26
9450
Clojure Web 开发-- Ring 使用指南
Clojure 学习入门(6)—— 函数定义
简短的函数可以使用#(),%表示唯一的参数;%1、%2 ..依次表示第1、2、..个参数;%&表示所有参数,如下: 
阳光岛主
2019/02/18
8270
clojure基础入门(一)
最近在看storm的源码,就学习分享下clojure语法。 阅读目录: 概述 变量 运算符 流程控制 总结 概述 clojure是一种运行在JVM上的Lisp方言,属于函数式编程范式,它和java可以方便的互相调用,这样开发的程序可以很好的结合java和clojure的优点(storm),这跟Net中C#和F#的角色一样。 安装java1.6以上的JDK,下载地址。 下载clojure的环境 包,下载地址。 解压后用命令行进入到clojure目录下,输入下面命令进入REPL命令行交互界面: jav
蘑菇先生
2018/05/21
1.4K0
函数式编程简介
1900年,Hilbert 提出了数学界悬而未决的10大问题,后续陆续添加成了23个问题,被称为著名的 Hilbert 23 Problem。针对其中第2个决定数学基础的问题——算术公理之相容性,年轻的哥德尔提出了哥德尔不完备定理,解决了这个问题形式化之后的前两点,即数学是完备的吗?数学是相容的吗?哥德尔用两条定理给出了否定的回答。
lambeta
2018/08/17
1.8K0
函数式编程简介
Clojure 学习入门(17)—— 异常处理
异常处理 Clojure代码里面抛出来的异常都是运行时异常。当然从Clojure代码里面调用的java代码还是可能抛出那种需要检查的异常的。
阳光岛主
2019/02/18
3860
Clojure 学习入门(7)—— 连接mysql
Clojure的contrib包中实现了对现有JDBC的封装,在wiki上有连接,该页面上包含了对不同的数据库的连接方法和基本的操作,但是这个页面上没有提供足够的信息,足够一个初学者能够使用Clojure来完成一个SQL操作。本文中我们将利用Clojure和Lein工具,简介一下做开发的基础。当然网上也有非常多对Clojure的SQL操作进行封装的库,我们这里没有使用。
阳光岛主
2019/02/18
1.2K0
Clojure 学习入门(7)—— 连接mysql
Clojure集合管道函数练习
TDD讨论组里的申导最近在B站直播了Martin Fowler的经典文章Refactoring with Loops and Collection Pipelines中谈到的利用集合管道对循环进行函数式重构。视频地址在这里,申导的翻译在这里。组织者小波(Seaborn Lee)趁机出了一道关于集合管道函数题目。我就想啊,论函数式编程,舍Clojure其谁?而且我在Clojure很少能写出loop... recur这样偏底层的循环代码。话不多说,撸起袖子开工。
lambeta
2018/08/17
1.2K0
Clojure文件操作和惰性序列
数据一般都是存储在纯文本文件当中,存储的形式多种多样。本文,我会介绍如何在Clojure中读取和写入这些数据。
lambeta
2018/08/17
3.2K0
Clojure component 设计哲学
Component 是一个微型的 Clojure 框架用于管理那些包含运行时状态的软件组件的生命周期和依赖。
lambeta
2018/10/11
1.1K0
Clojure 学习入门(5)—— 关键字
一、创建: Keyword: 关键字是一个内部字符串; 两个同样的关键字指向同一个对象; 通常被用来作为map的key。 
阳光岛主
2019/02/18
6630
Clojure 学习入门(3)—— 数字类型
一、算术运算 加法+:加法函数(+)接受任意数值类型的参数,返回它们的和;没有参数时返回0。 
阳光岛主
2019/02/18
6770
Clojure 运行原理之字节码生成篇
上一篇文章讲述了 Clojure 编译器工作的整体流程,主要涉及 LispReader 与 Compiler 这两个类,而且指出编译器并没有把 Clojure 转为相应的 Java 代码,而是直接使用 ASM 生成可运行在 JVM 中的 bytecode。本文将主要讨论 Clojure 编译成的 bytecode 如何实现动态运行时以及为什么 Clojure 程序启动慢,这会涉及到 JVM 的类加载机制。
飞驰的西瓜
2022/07/26
8150
Clojure 运行原理之字节码生成篇
Clojure 学习入门(18)—— 数据类型
Clojure是一种动态类型语言,这意味着你在程序中永远不需要明确定义符号、函数、或者参数的数据类型。但是,所有的值仍然有一个类型。字符串时是字符串,数字是数字,列表是列表,等等。如果你尝试执行一个类型不支持的操作,将会在运行时产生错误。写代码时避免这种事情,是程序员的责任。对于有动态语言背景的人来说是很自然的事情,而那些只使用静态语言的人需要一些转变。
阳光岛主
2019/02/18
2.6K0
(cljs/run-at (JSVM. :all) "一次说白DataType、Record和Protocol")
前言  在项目中我们一般会为实际问题域定义领域数据模型,譬如开发VDOM时自然而言就会定义个VNode数据类型,用于打包存储、操作相关数据。clj/cljs不单内置了List、Vector、Set和Map等数据结构,还提供deftype和defrecord让我们可以自定义数据结构,以满足实际开发需求。 定义数据结构从Data Type和Record开始  提及数据结构很自然就想起C语言中的struct,结构中只有字段并没有定义任何方法,而这也是deftype和defrecord最基础的玩法。 示例 (de
^_^肥仔John
2018/01/18
8640
Lisp 学习资源集锦
http://acl.readthedocs.io/en/latest/zhCN/index.html
一个会写诗的程序员
2018/08/17
1.9K0
Clojure 学习入门(15)—— 条件判断
一、标准的流程控制 if:  将一个判断表达式作为它的第一个参数进行求值。如果求值为true,那么就返回它的第二个参数(相当于“then”子句)的求值结果。如果结果为false(包括nil)就返回第三个参数的求值结果(相当于“else”子句),前提是有提供第三个参数并且不为空。 
阳光岛主
2019/02/18
8990
命令行中 tree 的多重实现
解题思路 利用递归,将目录转换成 {:name: ".", :children: []} 结构 对于第一层目录名,前缀装饰成 T_branch = "├── "或者 L_branch = "└── " 对于子目录,前缀装饰成 I_branch = "│ "或者SPACER = " " 举例如下: . ├── tree.py # 不是最后一项,所以使用 T_branch 前缀 ├── files.py ├── lists.py ├── tuples.py ├── resources │ └── RE
lambeta
2018/08/17
6710
Clojure 学习入门(8)—— 连接mongodb
project.clj 文件添加monger依赖: [com.novemberain/monger "1.5.0"]
阳光岛主
2019/02/18
1K0
Clojure 学习入门(8)—— 连接mongodb
Thinking in React Implemented by Reagent
前言  本文是学习Thinking in React这一章后的记录,并且用Reagent实现其中的示例。 概要 构造恰当的数据结构 从静态非交互版本开始 追加交互代码 一、构造恰当的数据结构 Since you’re often displaying a JSON data model to a user, you’ll find that if your model was built correctly, your UI (and therefore your component structure)
^_^肥仔John
2018/01/18
6570
python3学习案例
""" 请打印出 1024 * 768 = *** """ shu = 1024 * 768 print("1024 * 768 = %d" %shu) """ 请打印出以下变量的值: # -*- coding: utf-8 -*- n = 123 f = 456.789 s1 = 'Hello, world' s2 = 'Hello, \'Adam\'' s3 = r'Hello, "Bart"' s4 = r'''Hello, Lisa!''' """ n = 123 f = 456789 / 100
py3study
2020/01/03
7390
相关推荐
Clojure Web 开发-- Ring 使用指南
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验