诸城做网站的公司招标信息网

当前位置: 首页 > news >正文

诸城做网站的公司,招标信息网,怎么看网站用什么代码做的,网站外链暴涨与君共勉#xff1a;生命不息#xff0c;学习不止#xff0c;切忌浮躁#xff0c;静下心来#xff0c;每天进步一点点。 Clojure简介 Clojure是一门运行在JVM上面的Lisp方言#xff0c;其它的Lisp方言还有Scheme、Common Lisp等。Lisp相关的著名书籍有《计算机程序的构…与君共勉生命不息学习不止切忌浮躁静下心来每天进步一点点。 Clojure简介 Clojure是一门运行在JVM上面的Lisp方言其它的Lisp方言还有Scheme、Common Lisp等。Lisp相关的著名书籍有《计算机程序的构造和解释》简称SICP、《The Little Schemer》、《黑客与画家》。 Clojure可以和Java代码互操作它会编译成字节码运行在JVM上面所有的Java生态都可以为Clojure所用。 Clojure的语法比较怪异采用前缀表达式比如一般编程语言中的34、5-3、add(4,6)在Clojure中统一写成( 3 4)、(- 5 3)、(add 4 6)对编译器很友好如果你了解抽象语法树的形式会很好理解且因为这种统一无需记忆所谓的操作符优先级而且语法元素也很少正是因为这种简洁Lisp系的语言的数据和代码被统一了起来即所谓的代码即数据代码本身就是它的数据结构比如( 3 4)是代码但是它作为读取器处理的对象可以将它看作list类型的数据因为list类型的数据就是(1 2 3)或( 4 5)这种形式。 普遍存在的数据结构 大部分编程语言都有集合类型比如array、list、set、map等等它们都有自己的具体实现。 比如在静态类型语言中如Java、Rust数组的元素都是连在一起的数组的元素类型都是一致的这样根据下标访问数组元素可以简单地通过数组指针加上数组元素占用的字节大小乘以下标快速定位到特定元素。动态语言中如JavaScript中数组的元素类型不要求是一致的比如可以这样声明一个数组 let arr [2,花无缺]; // 数组元素可以是Number和String类型混在一起的比如list在Java中分ArrayList和LinkedListLinkedList是通过链表来实现的Clojure中的list也是通过链表来实现的链表元素在内存中可能相隔很远链表实现的优点是访问链表头特别快在链表头追加一个元素特别快但是访问链表中其它的元素比较慢需要一个一个地跳转。 Clojure中的集合类 Clojure中常用的集合类型的数据结构有list、vector、set、map等它们有字面量表示方式即在代码中写死的表示也可以通过函数创建它们。 例如: ;;list的字面量需要有一个单引号在小括号前面如果不加Clojure会认为(1 2 3)中的1是一个函数调用从而报错 (def this-is-list (1 2 3)) ;;将包含1、2、3这三个数字的list绑定到this-is-list变量上 (def this-is-list2 (list 1 3 4)) ;;通过list函数创建一个list;;vector的字面量是中括号包起来的 (def this-is-vector [江苏 南京 江宁]) ;;通过字面量创建一个vector其中元素是三个字符串 (def this-is-vector2 (vector :name :sex :age)) ;;通过vector函数创建一个vector其中元素是三个关键字keyword;;set的字面量要用#{}包起来 (def this-is-set #{2 3 4}) ;;字面量方式 (def this-is-set2 (set [4 5 6]));;通过set函数创建注意set函数后面的参数必须是集合类型这儿用一个vector作为参数 (def this-is-set3 (set (4 5 6)));;通过set函数创建注意set函数后面的参数必须是集合类型这儿用一个list作为参数;;map的字面量要用大括号{}包起来Clojure中的map的各个key-value之间可以不用逗号分割 (def this-is-map {:name 明月 :address 无双城}) ;;字面量方式创建mapkey的类型是关键字keywordvalue的类型是字符串 (def this-is-map2 (hash-map :name 第二梦 :address 绝情谷));;通过hash-map函数创建mapClojure的哲学 Clojure是一门特别推崇函数式编程范式的编程语言它有一个设计哲学 It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures. —Alan Perlis 即在1种数据结构上定义100中操作方法比在10种数据结构上定义10种方法更好。 也就是说Clojure编程语言不像面向对象编程语言那样提倡多创建自己的类型然后再在每个类型上添加方法通过方法之间的调用来构造复杂的系统比如在Java中你可以自定义User类、Employee类每个类都有自己的方法。然而这些自定义类的字段仍不可免俗地是String、Integer、Boolean这些类型。所以Clojure的设计者认为提供map类型的数据结构里面可以放各种类型然后通过给map提供丰富多彩的函数操作一样可以构造复杂系统。 比如在Java中定义的User类可能是这样的 public class User {private String name;// 通过给User类定义name方法来访问name字段public String getName(){return this.name;}private int age;// 通过给User类定义getAge方法来访问age字段public int getAge(){return this.age;} }在Clojure中我们可以将用户信息放到map中然后通过map的key来访问用户信息 (def user {:name 江别鹤 :age 50}) ;; 通过 :name字段来获取姓名 (user :name) ;; 或者通过 :name关键字作为函数来使用没错Clojure中的关键字可以作为函数来使用 (:name user) ;; 江别鹤 ;; 通过 :age字段来获取年龄 (user :age) ;; 或者通过 :age关键字作为函数来使用 (:age user) ;; 50上面我们介绍过Clojure中的几种常见的集合类型在Clojure的设计哲学的指导下Clojure中的集合类型上面有大量的函数可以使用比如 ;; 提到的函数有点多耐心点为了后面讲的抽象做铺垫 ;; empty?函数没错Clojure中的函数或变量中可以包含问号、中划线、感叹号等 (empty? [1 3 4]) ;; 判断vector是否为空 (empty? (慕容仙 江玉凤 苏樱)) ;; 判断list是否为空 (empty? #{23 45 呵呵}) ;; 判断vector是否为空 (empty? {:name 花无缺 :age 20}) ;; 判断map是否为空;; seq函数返回序列 (seq [23 4 5]) ;; 返回(23 4 5) (seq (43 5 66)) ;; 返回(43 5 66) (seq #{45 23 2}) ;; 返回(2 23 45) (seq {:name 怜星 :sister 邀月}) ;; 返回([:name 怜星] [:sister 邀月]);; first函数 (first [23 4 5]) ;; 获取vector的第一个元素返回23 (first (43 5 66)) ;; 获取list的第一个元素返回43 (first #{45 23 2}) ;; 获取set的第一个元素返回2 (first {:name 怜星 :sister 邀月}) ;; 获取map的第一个key-value对返回[:name 怜星];; rest函数获取集合第一个元素之外的元素列表 (rest [23 4 5]) ;; 获取vector的第一个元素之外的元素(4 5) (rest (43 5 66)) ;; 获取list的第一个元素之外的元素返回(5 66) (rest #{45 23 2}) ;; 获取set的第一个元素之外的元素返回(23 45) (rest {:name 怜星 :sister 邀月}) ;; 获取map的第一个key-value对之外的元素返回 ([:sister 邀月]);; map函数类似Java中stream上面的map函数对每一个元素应用一次函数 (defn say-hello x) ;; 定义一个say-hello函数对入参拼上一个Hello,字符串前缀 (map say-hello [南京 兰州]) ;; 返回(Hello,南京 Hello,兰州) (map say-hello #{江宁 百家湖}) ;; 返回(Hello,江宁 Hello,百家湖);; reduce函数在Clojure中-*/这些符号都是函数 (reduce [2 3 4]) ;; 对vector中的所有元素求和返回9 (reduce * (4 6 7)) ;; 对list中的所有元素求乘积返回168;; conj函数往集合中追加元素 (conj [2 3 4] 5 6 7) ;; 返回 2 3 4 5 6 7 ;; 返回1 2 3 ;; Clojure中的list底层实现为链表追加元素的时候放在表头最快所以返回(4 1 2 3) (conj (1 2 3) 4 5) ;; Clojure中的list底层实现为链表追加元素的时候放在表头最快返回(5 4 1 2 3) (conj {:name 张无忌 :age 25} [:first-girl-friend 周芷若]) ;; 返回{:name 张无忌, :age 25, :first-girl-friend 周芷若};; cons函数往序列中添加元素 (cons 3 [1 2 3]) ;; 返回(3 1 2 3) (cons 5 (2 3)) ;; 返回(5 2 3) (cons 6 #{5 6}) ;; 返回(6 6 5) 介绍这么多函数有的函数返回的是集合本来的类型。比如 对于conj函数。入参是vector返回的还是vector入参是list返回的还是list。 有的函数返回的和入参的集合类型不同比如 cons函数不管入参是什么类型返回的都是小括号包起来的输出。 是否有点凌乱 抽象的力量 让我们站在更高的角度来审视这个问题。我们知道对于Java的List、Set、Map一些工具类如CollectionUtils提供了isEmpty、isNotEmpty来判断集合是否为空。对于List、Set、Map中的元素想挨个处理可以通过这些集合上的stream方法转换成流以后使用map、filter等方法来处理。 也就是说我们通过提供更高层次的抽象来屏蔽掉了底层数据结构的不同让上层可以用统一的方式来处理底层的数据。 所谓的抽象不过是一组操作的集合满足了这些操作的集合的数据类型就是这种抽象的一种具体实现。比如汽车是一种抽象它有前进、转弯、后退、加油、开窗等操作具体的类型可以是大巴车、小轿车、公交车。 然而对一组类型进行抽象只能提取它们共同部分的信息比如集合都有获取第一个元素、获取第n个元素、遍历元素这些操作所以这些操作都可以提取成一种更高层次的抽象在Clojure中表现为first、nth、map这些函数然而真正落实到具体的数据结构上的时候它们又不同所以需要将它们转换成中间的一层统一的抽象在Clojure中就是所谓的seq或者叫sequence即序列当各种各样的数据结构转换成seq就可以对seq进行first、second、rest、map等操作。就像Java中的各种集合调用了stream之后转换成了统一的抽象后才可以使用map、filter、collect等操作。 Clojure中的两大抽象 Clojure有两个重要的抽象collection和seq即集合和序列Clojure的list、vector、map、set都实现了这两大抽象。前面我们说过所谓的抽象就是一组操作的集合符合某一个抽象的类型必定都具备这个抽象中的所有操作而满足一个抽象中的所有操作的类型也可以实现为这个抽象进而可以被针对这个抽象实现的所有的函数使用。 collection的抽象中的主要操作有empty?、contains?、every等它是将数据作为一个整体进行处理的 seq的抽象中的主要操作有first、second、rest、map等它是将数据作为一个序列从而可以一个一个地处理。 当我们将list、vector、set、map数据类型传递到形参是seq类型的函数式会发生隐式转换会先调用seq函数将其转换成seq抽象比如 ;; 下面两个是等价的返回的都是4因为(seq #{2 3 4})返回的是(4 3 2)这个seq (first #{2 3 4}) (first (seq #{2 3 4}))参考资料 1.《Clojure for the brave and true》