几分钟内学习 Clojure

2024-02-15 03:18
文章标签 学习 clojure 几分钟

本文主要是介绍几分钟内学习 Clojure,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

Clojure源码托管在:github

在线练习编译环境: himera


learnclojure.clj 示例:

; 分号作为注释的开始; 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.Datejava.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


这篇关于几分钟内学习 Clojure的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/710311

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件