<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>SweatBuffer`s Blog</title>
  <subtitle>发酵的奶酪</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://www.sweatbuffer.com/"/>
  <updated>2017-04-28T13:15:49.000Z</updated>
  <id>http://www.sweatbuffer.com/</id>
  
  <author>
    <name>SweatBuffer</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Functional programming in Scala(三)</title>
    <link href="http://www.sweatbuffer.com/2017/04/28/title:%20Functional%20programming%20in%20Scala(%E4%B8%89)/"/>
    <id>http://www.sweatbuffer.com/2017/04/28/title: Functional programming in Scala(三)/</id>
    <published>2017-04-28T12:43:24.000Z</published>
    <updated>2017-04-28T13:15:49.000Z</updated>
    
    <content type="html"><![CDATA[<p>#Scala/Chapter3#</p>
<h1 id="Chapter3-Functional-data-structures-函数式数据结构"><a href="#Chapter3-Functional-data-structures-函数式数据结构" class="headerlink" title="Chapter3 Functional data structures (函数式数据结构)"></a>Chapter3 Functional data structures (函数式数据结构)</h1><p>我们讲函数型程序并不<strong>更新 变量</strong>或者<strong>修改 可变的数据结构</strong> 那我们会提出疑问：</p>
<ol>
<li>在函数式编程里面 什么样的(what sort of )数据结构 我们可以用</li>
<li>我们如何在 Scala 中定义他们</li>
<li>我们如何操作(operate)这些数据结构</li>
</ol>
<p>在这章我们将会学习<strong>函数式 数据结构</strong> (<strong>functional data structures</strong> )的概念和如何使用他们。我们将借此机会介绍 在函数式编程里 数据类型(data type)是如何定义的，学习 <strong>模式匹配</strong>(<strong>pattern matching</strong>)相关的技术，练习编写和归纳 <strong>纯粹的函数</strong>(<strong>pure functions</strong>)。</p>
<h2 id="3-1-Defining-functional-data-structures-定义-函数式数据结构"><a href="#3-1-Defining-functional-data-structures-定义-函数式数据结构" class="headerlink" title="3.1 Defining functional data structures (定义 函数式数据结构)"></a>3.1 Defining functional data structures (定义 函数式数据结构)</h2><p>一个函数式数据结构只有在使用 纯粹的函数(<strong>pure functions</strong>)的时候使用。记住，一个纯粹函数必须不能直接改变data 或者 执行其他的 <strong>side effect</strong> (附加的东西 比如在一个买咖啡的函数里面，执行连接信用卡server的代码 这个就属于 side effect)。<br><strong>所以 函数式数据结构定义的内容是不可改变的</strong>。<br>例如：在Scala里的 List() 和 Nil 就是不可变的。在进行List 操作的时候 比如 计算  3 + 4 我们并不改变 3或者4本身 而是新生成一个变量 7. 两个input 都不改变。连接两个链表操作也是啊， append 链表A 和 链表B 他并不改变输入本身，而是新建立一个链表。<br>这是不是意味着我们做了很多额外的复制工作呢？其实不是的。首先我们看一下最普遍的函数数据结构，单链表 (Singly linked list)。</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">sealed</span> <span class="class"><span class="keyword">trait</span> <span class="title">List</span>[+<span class="type">A</span>]</span></div><div class="line"><span class="keyword">final</span> <span class="keyword">case</span> <span class="class"><span class="keyword">class</span> <span class="title">Cons</span>[+<span class="type">A</span>](<span class="params">head: <span class="type">A</span>,tail: <span class="type">List</span>[<span class="type">A</span>]</span>)<span class="keyword">extends</span> <span class="title">List</span>[<span class="type">A</span>]</span></div><div class="line"><span class="keyword">final</span> <span class="keyword">case</span> <span class="class"><span class="keyword">object</span> <span class="title">Nil</span> <span class="keyword">extends</span> <span class="title">List</span>[<span class="type">Nothing</span>]</span></div></pre></td></tr></table></figure>
<p><strong>sealed trait</strong> 是什么意思？<br><strong>trait</strong> 是一个抽象的接口(abstract interface) 可以选择性的包含一些方法的实现。在这里声明一个 <strong>trait</strong> 叫做 <strong>List</strong> ，不含有任何方法。添加<strong>sealed</strong>在前面意味着 这个 trait 的所有的实现必须在这个文件里面声明。<br>这里面有两种实现 或者说 List 的 数据 构造(data constructors)  来代表 List 可以使用的的两种形式。<br>一个List 可以为空，由 Nil 来指示，不为空的时候由 Cons来指示。一个不为空的List 由 | Head | Tail | 来组成。Tail 是 表示剩余元素的一个List 。<br>正因为函数可以是多态的，数据类型也一样，通过添加 类型参数(type parameter) [+A]  在sealed trait List 后面 然后在 Cons data constructor 里面使用这个 A 类型的参数，我们声明 这个 List 数据类型为多态的意味着 我们可以使用相同的定义 对一个 Int 元素 List[Int], Double 元素(List[Double]), String 元素(List[String]) 等等。“<strong>+</strong>” 意味着 类型参数 A 是 协变的，共变的(<strong>Covariant</strong>). 意味着 A 是一个List 的 共变，积极参数。（个人理解这句话的意思是：List 和 参数 A 是共同， A 是Int，List 类型就是 List[Int], 就怎么说呢 他俩一起变化，一起等价这种概念吧)</p>
<p>例如：<br><strong>Covariant</strong>: For all types x and y .</p>
<ul>
<li>if x &lt;: y, then List[x] &lt;: List[y] (&lt;:表示继承关系中的辈分高低)</li>
<li>If not annotated, parameter is invariant, meaning there is no subtype relationship List[x] and List[y]<br>就是如果 参数有父子关系的话，那么List 也具有 父子关系。(个人理解)</li>
</ul>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">val</span> ex1:<span class="type">List</span>[<span class="type">Double</span>] = <span class="type">Nil</span></div><div class="line"><span class="keyword">val</span> ex2:<span class="type">List</span>[<span class="type">Int</span>] = <span class="type">Cons</span>(<span class="number">1</span>,<span class="type">Nil</span>)</div><div class="line"><span class="keyword">val</span> ex3:<span class="type">List</span>[<span class="type">String</span>] = <span class="type">Cons</span>(<span class="string">"a"</span>, <span class="type">Cons</span>(<span class="string">"b"</span>,<span class="type">Nil</span>))</div></pre></td></tr></table></figure>
<p>一个数据构造函数声明 给我们一个方法去构造 这个数据类型的形式。例如：上面的三个👆式子。<br>Case object Nil 让我们写一个<code>Nil</code>去构造一个空的List ， case class Cons 让我们写 <code>Cons(“a”, Cons(“b”, Nil))</code> 去构造一个任意长度的单链表。<br>注意：因为List 是参数化的，A, 对A，这里有 可以被不同的类型实例化的多态函数。 ex2 实例化 A 类型的参数到 <strong>Int</strong> ， ex3 实例化为 <strong>String</strong>，ex1 很有趣，Nil 是被实例化为 List[Double]类型了，这是被允许的，因为空的List 没有元素，可以被看做任意类型。<br>“老艺术家”说 Nil 定义的时候是 继承了 List[Nothing] 这是所有List 类的 最小辈分的一种，可以是任何类的子类。顺便拓展一下 ：<br>继承关系： Animal类  &lt;- Cat类 &lt;- Kitty类                ————————<br>Animal<br>————————<br>^<br>————————<br>Cat<br>————————<br>^<br>————————<br>Kitty<br>————————<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Foo</span></span>&#123;</div><div class="line">	<span class="type">Cat</span> foo(<span class="type">Cat</span> c)</div><div class="line">&#125;</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Bar</span> <span class="keyword">extends</span> <span class="title">Foo</span></span>&#123;</div><div class="line">	<span class="type">Kitty</span>      	   (<span class="type">Kitty</span> c)</div><div class="line">		   + foo +</div><div class="line">	<span class="type">Animal</span>		   (<span class="type">Animal</span> c)</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>返回类型问题和参数类型的问题：<br>先说 <strong>~返回类型~</strong> 哦，<br>亲子关系： Animal类  &lt;- Cat类 &lt;- Kitty类 ，<br>那么在内存里的空间状态是：[ <em> </em> ] &lt; [ <em> </em> <em> ] &lt; [ </em> <em> </em> <em> </em> ] 顺序是相反的，因为子类要保证父母能有的成员变量，成员方法自己都持有，但是子类持有的 变量和方法，父母类就不一定有了。所以返回的时候你要返回Kitty类型，ok，没有问题，因为他的空间包含了Cat 所需要的空间大小，但是返回 Animal 惨了，Animal的比 Cat 小哎，调用的时候 会有问题。换个人性化思维思考：父类里面的foo是猫，那么子类的 foo 只可能是 猫这个大类里面的小类别：波斯猫，kitty猫，你返回一个爬行哺乳动物就不对了。<br><strong>~参数类型~</strong> ：参数是用来做 operation 的，那么父类的参数是Cat ，显然他需要用猫的某些技能或者特性，比如喵喵叫，舔自己，闻屁股，那么Bar 中的参数必然也要最起码满足这个要求，但是不许超出这个范围，你input 一个kitty特有的粉红色是猫这个类不具有的性质，那么就有问题了。<br>要保证在这里调用的东西，父类方法里面最起码都有。</p>
<p>综上所述：返回类型可以使本身，或者子类 往下走；参数类型可以是自己或者父类 往上走。好像延展的有点多了。。。<br>所以~~ Nil 是 List[ Nothing ], 在 Scala 里面，Nothing 是所有类型的子类，那么Nil 就是所有 List 类型的子类，所以 Nil 可以赋给任何类型的List 值。</p>
<p>添加补充一下：</p>
<h3 id="Scala-Convariance-and-Contravariance-逆变与协变"><a href="#Scala-Convariance-and-Contravariance-逆变与协变" class="headerlink" title="Scala Convariance and Contravariance(逆变与协变)"></a>Scala Convariance and Contravariance(逆变与协变)</h3><p>Function范式里面定义了函数的”入参”和”出参” 分别是“逆变”(Contravariance)和”协变”(Convariance)的。</p>
<p>所以A=&gt;B这样的函数类型，也可以有继承关系的。<br>我们做个测试，先简单些，只看<strong>出参类型</strong>的(协变容易理解些)，A=&gt;B和A=&gt;C两个函数类型;<br>如果C extends B 则A=&gt;C 是 A=&gt;B的子类型<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">scala&gt; <span class="class"><span class="keyword">class</span> <span class="title">A</span></span>; <span class="class"><span class="keyword">class</span> <span class="title">Cats</span></span>; <span class="class"><span class="keyword">class</span> <span class="title">Kitty</span> <span class="keyword">extends</span> <span class="title">Cats</span></span></div><div class="line"> </div><div class="line"><span class="comment">//定义A=&gt;C类型的函数</span></div><div class="line">scala&gt; <span class="keyword">val</span> t2 = (p:<span class="type">A</span>)=&gt;<span class="keyword">new</span> <span class="type">Kitty</span></div><div class="line"> </div><div class="line"><span class="comment">//可以把 A=&gt;C类型的函数赋值给 A=&gt;B类型的</span></div><div class="line">scala&gt; <span class="keyword">val</span> t3:<span class="type">A</span>=&gt;<span class="type">Cats</span> = t2</div><div class="line"> </div><div class="line"><span class="comment">//或直接把t2造型为 A=&gt;Cats</span></div><div class="line">scala&gt; t2.asInstanceOf[<span class="type">A</span>=&gt;<span class="type">Cats</span>]</div></pre></td></tr></table></figure></p>
<p>再看看<strong>入参类型</strong>，这个是逆变，继承关系正好相反。<br>假设: B=&gt;A, C=&gt;A 如果 C extends B 则 B=&gt;A 是 C=&gt;A 的子类型<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">scala&gt; <span class="class"><span class="keyword">class</span> <span class="title">R</span></span>; <span class="class"><span class="keyword">class</span> <span class="title">Cats</span></span>; <span class="class"><span class="keyword">class</span> <span class="title">Kitty</span> <span class="keyword">extends</span> <span class="title">Cats</span>  </span></div><div class="line"> </div><div class="line"><span class="comment">//定义Cats=&gt;R类型的函数</span></div><div class="line">scala&gt; <span class="keyword">val</span> f1 = (x:<span class="type">Cats</span>)=&gt;<span class="keyword">new</span> <span class="type">R</span></div><div class="line"> </div><div class="line"><span class="comment">//把Cats=&gt;R类型的函数赋值给 Kitty=&gt;R 类型的</span></div><div class="line">scala&gt; <span class="keyword">val</span> f2:<span class="type">Kitty</span> =&gt;<span class="type">R</span> = f1</div><div class="line"> </div><div class="line"><span class="comment">//或直接造型</span></div><div class="line">scala&gt; f1.asInstanceOf[<span class="type">Kitty</span>=&gt;<span class="type">R</span>]</div></pre></td></tr></table></figure></p>
<p>协变和逆变的场景与java泛型的”PECS原则”一致</p>
<p>PECS 是Joshua Bloch在《Effictive Java》里提出的一个原则。<br>当参数(容器)是一个生产者(producer)提供元素给你的代码来用(即容器只读),那么容器的泛型应该使用:<br><code>Collection&lt; ? extends T &gt;</code></p>
<p>当参数(容器)作为一个消费者(consumer)来消费你提供的数据(即容器可写),那么容器的泛型应该使用:<br><code>Collection&lt; ? super T &gt;</code></p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">object</span> <span class="title">List</span></span>&#123;</div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">sum</span></span>(xs: <span class="type">List</span>[<span class="type">Int</span>]):<span class="type">Int</span> = ???</div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">product</span></span>(xs:<span class="type">List</span>[<span class="type">Double</span>]):<span class="type">Double</span> = ??</div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">apply</span></span>[<span class="type">A</span>](as: <span class="type">A</span>*):<span class="type">List</span>[<span class="type">A</span>] = ?</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>每一个 数据构造器 同样引入 模式(pattern) 可以被用于 模式设计，就像在 sum 和 product 方法里一样</p>
<hr>
<h2 id="3-2-Pattern-matching-模式匹配"><a href="#3-2-Pattern-matching-模式匹配" class="headerlink" title="3.2 Pattern matching (模式匹配)"></a>3.2 Pattern matching (模式匹配)</h2><p>仔细的看 <strong>sum</strong> 和 <strong>product</strong> 的细节，我们放入了 object List 里面，有时候叫做 Object List 的 <strong>伴生对象</strong> (<strong>companion object</strong>)。</p>
<p><strong>伴生对象</strong>： 我们除了声明 ~数据类型~ 和 ~数据构造函数~ 之外常常声明 ~伴生对象~。 这是和数据类型有着一样的名字(这里是 List ),我们放入多种方便的函数 到对象中 为了创建或者使用这种数据类型的值。(这句话怪哦)<br>例如我们希望一个函数 <code>def fill[A](n:Int, a:A):List[A]</code> 创建 一个List 里面有n个元素a，这个List 的伴生对象将会是一个好的地方。伴生对象不仅是在Scala里面的一种约定(Convention)。我们可以叫 这个 模块 Foo 如果我们希望，但是叫他 List 会很明确的显示 这个模块包含着关于 list 的一些方法。</p>
<p>下面的定义都使用了 模式匹配(pattern matching):<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">sum</span></span>(ints: <span class="type">List</span>[<span class="type">Int</span>]):<span class="type">Int</span> = ints <span class="keyword">match</span>&#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; <span class="number">0</span></div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(x,xs) =&gt; x + sum(xs)</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">product</span></span>(ds: <span class="type">List</span>[<span class="type">Double</span>]): <span class="type">Double</span> = ds <span class="keyword">match</span>&#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; <span class="number">1.0</span></div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(<span class="number">0.0</span>, _) =&gt; <span class="number">0.0</span></div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(x,xs) =&gt; x * product(xs)</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>这些是递归定义，写方法的时候 Scala等函数式编程很喜欢递归。Pattern matching 有点像 switch 文， 首先有一个 expression 像 ds 在 match 前面，然后每个 case 会有各自相应的 pattern 像 Cons(x,xs) 然后 =&gt; 后面跟的是 结果。如果 target expression 满足某个case 里的 pattern 那么就实现pattern 对应的 结果。如果 有 满足多个case 的情况，选择最先匹配到的 pattern 来执行。<br>看一下更多的例子：</p>
<ul>
<li><code>List(1,2,3) match {case _ =&gt; 42}</code> 输出值为42，因为 ‘_’ 意味着无论是什么值，都可以匹配，任意一种情况都会执行这个pattern。</li>
<li><code>List(1,2,3) match {case Cons(h,_) =&gt; h}</code> 这种情况会输出列表中的头，也就是说1，这种模式把List 中的 Head 和 Tail 分开了，值得我们学习哦。</li>
<li><code>List(1,2,3) match {case Cons(_,t) =&gt; t}</code> 这段代码则是不管Head 是什么，我只要Tail 并且输出Tail 所以输出结果是 List(2,3)</li>
<li><code>List(1,2,3) match {case Nil =&gt; 42}</code>会导致 <strong>MatchError</strong>错误发生。</li>
</ul>
<p>List(1,2,3) = Cons(1,Cons(2,Cons(3, Nil )))</p>
<p>那是什么决定了是否一个 pattern 匹配一个 expression 呢？ 一个 pattern 可能包含 <strong>~常量~</strong> 像 3 或者 “hi” ; <strong>~变量~</strong> 像 <strong>x</strong> 和 <strong>xs</strong>，匹配任何事情，由一个小写字母或者下划线开始的标识符标识； <strong>~数据构造函数~</strong> 像 <code>Cons(x,xs) or Nil</code>这种 只匹配相对应格式的值。这些模式的元素们可以被任意嵌套 — Cons(x1, Cons( x2, Nil)) , Cons(y1, Cons(y2, Cons(y3, _))) 是合法的模式。</p>
<p>一个模式匹配一个目标(如果在模式中存在一个变量的分配)到 这个目标的子表达式 (使其结构上和目标相等的 子表达式 )，对于一个匹配的 case , 结果得到的表达式 接下来将会 在他的本地范围里面 access 这些变量的赋值 。(哇塞 英文好难直译啊 T.T)<br>总结一下这段话：<br>问题：什么决定了是否一个 模式 匹配一个表达式呢？<br>答案：一个模式 可能包含 ：常量，变量，数据构造器(怪翻译)。模式中的这些元素们可以互相组合嵌套。<br>尚未总结完毕</p>
<hr>
<p><strong>Scala 中的可变函数(Variadic functions in Scala)</strong><br><strong>List</strong> 对象中的 <strong>apply</strong> 函数 就是一个 <strong>~可变函数~</strong> 意味着它允许或者说接受 0 或者更多A类型的参数：<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">apply</span></span>[<span class="type">A</span>](as: <span class="type">A</span>*): <span class="type">List</span>[<span class="type">A</span>] = &#123;</div><div class="line">	<span class="keyword">if</span> (as.isEmpty) <span class="type">Nil</span></div><div class="line">	<span class="keyword">else</span> <span class="type">Cons</span>(as.head, apply(as.tail: _*))</div><div class="line">	实际：</div><div class="line">	<span class="keyword">if</span> (as.isEmpty) <span class="type">Nil</span></div><div class="line">	<span class="keyword">else</span> as.head::apply(as.tail: _*)</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>对于 数据类型，这是一个常见的俗话去有一个可变的apply 方法 在伴生对象中方便的构建数据类型的实例。通过调用这个方法 apply 然后在伴生对象中替换他，我们可以和语法一样调用它，就像 List(1,2,3,4) 或者 List(“Hi”,”bye”), 和许多我们希望用逗号分开一样。<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">apply(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>)</div><div class="line">res24: <span class="type">List</span>[<span class="type">Int</span>] = <span class="type">Cons</span>(<span class="number">1</span>,<span class="type">Cons</span>(<span class="number">2</span>,<span class="type">Cons</span>(<span class="number">3</span>,<span class="type">Cons</span>(<span class="number">4</span>,<span class="type">Cons</span>(<span class="number">5</span>,<span class="type">Nil</span>)))))</div><div class="line"><span class="type">List</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>)</div><div class="line">res31: <span class="type">List</span>[<span class="type">Int</span>] = <span class="type">List</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>)</div><div class="line">apply(<span class="number">1</span>,<span class="number">2</span>,<span class="string">"hello"</span>,<span class="string">"4"</span>)</div><div class="line">res49: <span class="type">List</span>[<span class="type">Any</span>] = <span class="type">Cons</span>(<span class="number">1</span>,<span class="type">Cons</span>(<span class="number">2</span>,<span class="type">Cons</span>(hello,<span class="type">Cons</span>(<span class="number">4</span>,<span class="type">Nil</span>))))</div></pre></td></tr></table></figure></p>
<p>如上图所示，调用 apply函数会把用逗号分开的值变成列表。</p>
<p>Variadic functions(可变函数)就是为 明确的创建和passing 一个元素序列( Seq of elements)提供一个语法糖🍬(<strong>syntactic sugar</strong>)。序列(Seq)是一个接口，在Scala库中，像 list, queue, vector 一样的一种数据结构。在 apply 里面 参数 as 将会被绑定成 Seq[A], 这个对象有着 head 方法 和 tail 方法。<br>特别的 _* 类型标注 允许我们 通过(pass) 一个 Seq 到一个可变成员方法。</p>
<hr>
<h2 id="3-3-Data-sharing-in-functional-data-structures-函数式数据结构中的数据共享"><a href="#3-3-Data-sharing-in-functional-data-structures-函数式数据结构中的数据共享" class="headerlink" title="3.3 Data sharing in functional data structures (函数式数据结构中的数据共享)"></a>3.3 Data sharing in functional data structures (函数式数据结构中的数据共享)</h2><p>当数据是不可变的时候，我们如何写函数，例如 从一个 List 中 add 或者 remove 元素？答案很简单，当我们添加一个元素1 到 一个列表的前头的时候，比如xs, 我们返回一个新的列表 Cons(1,xs)。 因为列表是不可改变的，我们不需要实际上的复制xs，只需要重新利用它，创建新的列表。我们叫它<strong>数据共享( Data sharing)</strong>。共享不可改变的数据常常使我们实现函数更加的高效；我们总可以返回不可改变的数据结构而不需要担心后面的数据修改我们的数据。并不需要悲观的通过复制不可变数据结构去避免<strong>修改</strong>和<strong>变形</strong>。</p>
<p>用同样的方式，从一个List <code>mylist = Cons(x,xs)</code>中移除头一个元素，我们只需要复制他的 <strong>tail</strong>就可以了。而 mylist 依旧存在和可用。我们说函数式数据结构是<strong>可持续的(persistent)</strong>， 意味着既有的参照关系绝对不会因为在数据结构上的操作而改变。</p>
<h3 id="数据共享的效率-The-efficiency-of-data-sharing"><a href="#数据共享的效率-The-efficiency-of-data-sharing" class="headerlink" title="数据共享的效率(The efficiency of data sharing)"></a>数据共享的效率(The efficiency of data sharing)</h3><p>数据分享的一个非常令人吃惊的例子就是 函数添加一个列表所有的元素到另一个列表的尾部：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">append</span></span>[<span class="type">A</span>](a1: <span class="type">List</span>[<span class="type">A</span>], a2: <span class="type">List</span>[<span class="type">A</span>]): <span class="type">List</span>[<span class="type">A</span>] = </div><div class="line">	a1 <span class="keyword">match</span>&#123;</div><div class="line">		<span class="keyword">case</span> <span class="type">Nil</span> =&gt; a2</div><div class="line">		<span class="keyword">case</span> <span class="type">Cons</span>(h,t) =&gt; <span class="type">Cons</span>(h, append(t,a2))</div><div class="line">		实际：</div><div class="line">		<span class="keyword">case</span> <span class="type">Nil</span> =&gt; a2</div><div class="line">		<span class="keyword">case</span> h::t =&gt; h::append(t,a2)</div><div class="line"></div><div class="line">	&#125;</div></pre></td></tr></table></figure>
<p>请注意这个定义仅仅是复制值 直到第一个链表的尾部，所以他的运行时间和内存利用是仅仅取决于 a1 的长度的。剩下的列表仅仅是指向 a2。如果我们要用两个<strong>数列(array)</strong>执行同样的操作的话，我们需要拷贝两个array 的所有的元素到输出上。所以在这种情况下，不可变链表是比数列更加高效的。</p>
<p>因为单链表的结构，任意时刻我们想要替换一个Cons的tail的时候，即使他是列表中的最后一个Cons，我们需要拷贝前面所有的Cons对象。写支持不同的高效操作的纯粹函数式数据结构需要我们找到一种聪明的方法去使用数据共享。现在我们并不准备自己亲自做所有的部分，我们可以很开心的使用Scala标准库，这里有定义好的<strong>纯粹函数式序列(pure functional sequence)</strong>的实现, <strong>~Vector~</strong> 。有着在常数时间下，随机的access(访问), updates, head,tail,init这些成员方法，常数时间下添加序列的头和尾。</p>
<hr>
<h3 id="提高高阶函数的类型推断"><a href="#提高高阶函数的类型推断" class="headerlink" title="提高高阶函数的类型推断"></a>提高高阶函数的类型推断</h3><p>高阶函数像 dropWhile 常常会被 匿名函数<strong>(anonymous functions)</strong> pass掉。看一个典型的例子：(dropWhile 函数式 当条件式子为假那么开始 不在看元素是否符合条件了，开始迭代序列 ,<br>即：符合条件的时候继续扫描下一个元素，直到条件不符合，返回剩下的元素的列表)</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">dropWhile</span></span>[<span class="type">A</span>](as: <span class="type">List</span>[<span class="type">A</span>],f:<span class="type">A</span>=&gt;<span class="type">Boolean</span>):<span class="type">List</span>[<span class="type">A</span>] = as <span class="keyword">match</span>&#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(h,t) <span class="keyword">if</span> (f(h)) =&gt; dropWhile(t,f)</div><div class="line">	<span class="keyword">case</span> e @ <span class="type">Cons</span>(h,t) =&gt; e</div><div class="line">	<span class="keyword">case</span> _ =&gt; <span class="type">Nil</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">dropWhile</span></span>[<span class="type">A</span>](l: <span class="type">List</span>[<span class="type">A</span>], f: <span class="type">A</span> =&gt; <span class="type">Boolean</span>): <span class="type">List</span>[<span class="type">A</span>] = l <span class="keyword">match</span> &#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(x,y) <span class="keyword">if</span>(f) =&gt; dropWhile(y,f)</div><div class="line">	<span class="keyword">case</span> _ =&gt; l</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>设计思路：match的时候可以 case Cons(x,y) if(f) 满足条件的时候要同时满足条件。</p>
<p>当我们用 匿名函数 f 调用这个方法的时候，我们必须区分 f 的参数 这里叫 x：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">val</span> xs: <span class="type">List</span>[<span class="type">Int</span>] = <span class="type">List</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>)</div><div class="line"><span class="keyword">val</span> ex1 = dropWhile(xs, (x: <span class="type">Int</span>) =&gt; x &lt; <span class="number">4</span>)</div></pre></td></tr></table></figure>
<p>这里如果不注释 x 的类型为 Int 的话会报错。<br>非常不幸的是我们需要规定 x 的类型是 Int。dropWhile的第一个参数是一个List[Int]， 所以函数的第二个参数必须符合Int。这是之前声明的时候定义好的。Scala 可以推断这个事实，如果我们把 dropwhile 归入到两个参数的链表中：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">dropWhile</span></span>[<span class="type">A</span>](as: <span class="type">List</span>[<span class="type">A</span>])(f: <span class="type">A</span> =&gt; <span class="type">Boolean</span>): <span class="type">List</span>[<span class="type">A</span>] = as <span class="keyword">match</span>&#123;</div><div class="line">		<span class="keyword">case</span> <span class="type">Cons</span>(h,t) <span class="keyword">if</span> f(h) =&gt; dropWhile(t)(f)</div><div class="line">		<span class="keyword">case</span> _ =&gt; as</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>调用这个版本 dropWhile 函数的语法像 dropWhile(xs)(f)。其实就是啦，dropWhile(xs) 返回一个函数，我们利用 f 来作为参数 调用这个函数，其实就是dropWhile 被curry化了。这样grouping 参数的原因是为了帮助 类型推断。我们现在可以不用注释的使用dropWhile函数了:</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">val</span> xs: <span class="type">List</span>[<span class="type">Int</span>] = <span class="type">List</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>)</div><div class="line"><span class="keyword">val</span> ex1: dropWhile(xs)(x =&gt; x &lt; <span class="number">4</span>)</div></pre></td></tr></table></figure>
<p>这里的 x 就没有注释 x 的类型。<br>更普遍的，当一个函数定义里面包含着多种参数 group，类型信息从左到右的贯穿这些参数 groups。这里第一个参数group 固定了 parameterA 为Int，所以他右边的都是Int，x就不需要注释了。</p>
<p>我们通常将我们函数的参数 group 和 排序到 多重参数列表中来最大化 类型推论。</p>
<hr>
<h2 id="3-4-Recursion-over-lists-and-generalizing-to-higher-order-functions-通过链表的递归调用和概述高阶函数"><a href="#3-4-Recursion-over-lists-and-generalizing-to-higher-order-functions-通过链表的递归调用和概述高阶函数" class="headerlink" title="3.4 Recursion over lists and generalizing to higher-order functions (通过链表的递归调用和概述高阶函数)"></a>3.4 Recursion over lists and generalizing to higher-order functions (通过链表的递归调用和概述高阶函数)</h2><p>让我们重新看一下 sum 和 product 的实现。我们非常 轻盈的实现了 product 从而 没有包含了检查 “ 0.0 逻辑 “的问题。</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">sum</span></span>(ints: <span class="type">List</span>[<span class="type">Int</span>]):<span class="type">Int</span> = ints <span class="keyword">match</span>&#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; <span class="number">0</span></div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(x,xs) =&gt; x + sum(xs)</div><div class="line">	改成 x::xs =&gt; x+sum(xs)</div><div class="line">&#125; </div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">product</span></span>(ds: <span class="type">List</span>[<span class="type">Double</span>]): <span class="type">Double</span> = ds <span class="keyword">match</span>&#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; <span class="number">1.0</span></div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(x,xs) =&gt; x * product(xs)</div><div class="line">	改成：<span class="keyword">case</span> x::xs =&gt; x* product(xs)</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>有没有注意到这两个函数是多么的相似，处理逻辑几乎一样。只是 处理数据的类型 一个是 Double 一个是 Int，撇开这个来看 不同点一个是 Nil 情况 返回值不同( 0 and 1.0)，操作符号不同(+ and * )。<br>无论何时，遇到这种重叠的情况，你都想把这种重叠 抽象出来，把子表达式拽出来作为参数。如果一个子表达式关联任何本地变量( + 关联 本地变量 x 和 xs ，product也一样)，把这个子表达式 放入采用这些变量作为参数的函数中。</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">foldRight</span></span>[<span class="type">A</span>,<span class="type">B</span>](as: <span class="type">List</span>[<span class="type">A</span>], z: <span class="type">B</span>)(f: (<span class="type">A</span>,<span class="type">B</span>) =&gt; <span class="type">B</span>) :<span class="type">B</span> =&#123;</div><div class="line">	as <span class="keyword">match</span>&#123;</div><div class="line">		<span class="keyword">case</span> <span class="type">Nil</span> =&gt; z</div><div class="line">		<span class="keyword">case</span> <span class="type">Cons</span>(x,xs) =&gt; f(x, foldRight(xs, z)(f))</div><div class="line">		改成：</div><div class="line">		<span class="keyword">case</span> x::xs =&gt; f(x,foldRight(xs,z)(f))</div><div class="line">	&#125;</div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">sum2</span></span>(ns: <span class="type">List</span>[int]) = &#123;</div><div class="line">	foldRight(ns, <span class="number">0</span>)((x,y) =&gt; x + y)	</div><div class="line">&#125;</div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">product2</span></span>(ns:<span class="type">List</span>[<span class="type">Double</span>]) = &#123;</div><div class="line">	foldRight(ns,d <span class="number">1.0</span>)(_ * _)	</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<ul>
<li>把 f 放入他自己的参数 group 在 as 和 z 之后，让 参数推断决定f 输入类型。</li>
<li><em> * </em> 是 (x, y) =&gt; x * y 更简明的一种注释。</li>
</ul>
<p>你看我们在编程的时候很多方法都有共同点，他们可能都有一个可以归纳的核心逻辑，然后把这个核心逻辑抽离出来就变成foldright了。</p>
<p>foldRight (右折叠)没有指定任何一种元素的参数类型，我们发现 当概括/一般化之后，返回值并不一定是元素一个类型的。一种描述 foldRight 做了什么就是: 他替换了List 的 构造器，用 z 和 f 替换了 Nil 和 Cons ：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="type">Cons</span>(<span class="number">1</span>, <span class="type">Cons</span>(<span class="number">2</span>, <span class="type">Nil</span>))</div><div class="line">f   (<span class="number">1</span>, f   (<span class="number">2</span>, z   ))</div><div class="line"></div><div class="line">foldRight(<span class="type">Cons</span>(<span class="number">1</span>, <span class="type">Cons</span>(<span class="number">2</span>, <span class="type">Cons</span>(<span class="number">3</span>, <span class="type">Nil</span>))), <span class="number">0</span>) ((x,y) =&gt; x+y )</div><div class="line"><span class="number">1</span> +	foldRight(<span class="type">Cons</span>(<span class="number">2</span>, <span class="type">Cons</span>(<span class="number">3</span>, <span class="type">Nil</span>)), <span class="number">0</span>) ((x,y) =&gt; x+y )</div><div class="line"><span class="number">1</span> +	(<span class="number">2</span> +	foldRight(<span class="type">Cons</span>(<span class="number">3</span>, <span class="type">Nil</span>), <span class="number">0</span>) ((x,y) =&gt; x+y ))</div><div class="line"><span class="number">1</span> +   (<span class="number">2</span> +  	(<span class="number">3</span> + (foldRight(<span class="type">Cons</span>(<span class="type">Nil</span>, <span class="number">0</span>) ((x,y) =&gt; x+y ))))</div><div class="line"><span class="number">1</span> + 	(<span class="number">2</span> +	(<span class="number">3</span> + (<span class="number">0</span>)</div><div class="line"><span class="number">6</span></div></pre></td></tr></table></figure>
<p>foldRight 遍历所有的路径，直到list 末尾。<br>为什么说foldRight 可能会有 栈溢出，因为他是 一层一层的迭代，在扫描到最后一个数之前所有的数都要留着，从最后一个数开始计算然后在往回一层一层计算，所以会有栈溢出的可能性。</p>
<p>再分析一下foldRight<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">foldRight</span></span>[<span class="type">A</span>,<span class="type">B</span>](as: <span class="type">List</span>[<span class="type">A</span>], z: <span class="type">B</span>)(f: (<span class="type">A</span>,<span class="type">B</span>) =&gt; <span class="type">B</span>) :<span class="type">B</span> =</div><div class="line">	as <span class="keyword">match</span>&#123;</div><div class="line">		<span class="keyword">case</span> <span class="type">Nil</span> =&gt; z</div><div class="line">		<span class="keyword">case</span> x::xs =&gt; f(x, foldRight(xs, z)(f))</div><div class="line">	&#125;</div></pre></td></tr></table></figure></p>
<p>两个参数()(), 所以前面foldRight[A][B], 看参数里面(List[A],z:B)这个没啥说的<br>(f: (A,B)=&gt;B ) 这个指的是 里面的参数是一个函数：参数为A 和 B，A为List中的元素类型，B就是z的类型，最后得出结果为类型B。然后里面的body也是很棒，返回 Cons(x,xs) =&gt; f( x, foldRight(xs,z)(f) ) 返回的是列表的第一个元素和后面的迭代的值经过 f 操作。</p>
<p>下面看看<strong>foldLeft</strong></p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">foldLeft</span></span>[<span class="type">A</span>,<span class="type">B</span>](as:<span class="type">List</span>[<span class="type">A</span>],z:<span class="type">B</span>)(f :(<span class="type">B</span>,<span class="type">A</span>) =&gt; <span class="type">B</span>):<span class="type">B</span> =as <span class="keyword">match</span>&#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(h,t) =&gt; foldLeft(t,f(z,h))(f)</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; z</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="type">Cons</span>(<span class="number">1</span>,<span class="type">Cons</span>(<span class="number">2</span>,<span class="type">Cons</span>(<span class="number">3</span>,<span class="type">Nil</span>)))</div><div class="line">f(<span class="number">3</span>,   f(<span class="number">2</span>,   f(<span class="number">1</span>,   z)))</div><div class="line"></div><div class="line">foldLeft(<span class="type">Cons</span>(<span class="number">1</span>, <span class="type">Cons</span>(<span class="number">2</span>, <span class="type">Cons</span>(<span class="number">3</span>, <span class="type">Nil</span>))), <span class="number">0</span>) ((x,y) =&gt; x+y )</div><div class="line">foldLeft(<span class="type">Cons</span>(<span class="number">2</span>, <span class="type">Cons</span>(<span class="number">3</span>, <span class="type">Nil</span>)), <span class="number">1</span>+<span class="number">0</span>) ((x,y) =&gt; x+y )</div><div class="line">foldLeft(<span class="type">Cons</span>(<span class="number">3</span>, <span class="type">Nil</span>), <span class="number">2</span>+<span class="number">1</span>+<span class="number">0</span>) ((x,y) =&gt; x+y ))</div><div class="line">foldLeft(<span class="type">Nil</span>, <span class="number">3</span>+<span class="number">2</span>+<span class="number">1</span>) ((x,y) =&gt; x+y ))))</div><div class="line"><span class="number">6</span></div></pre></td></tr></table></figure>
<p>你在看看这个左折叠的 z 的值是每次迭代都会更新一次的，然后每次的这个更新后的值在带入下一个函数里面，所以这个就不会有栈溢出的问题。<br>很神奇哦，就是明明是顺序运算但是却 写成这个样子。。<br>在这里他用List 的第一个的元素和参数z 进行 f 运算然后放入第二次迭代的参数进行第二次迭代。所以可以看做是一边运算一遍进行迭代。而foldright 则是一直迭代到底然后在返回来。<br>两者有啥区别？？</p>
<h3 id="考点！！-List-reverse-教授好像说会考-List-的-Reverse"><a href="#考点！！-List-reverse-教授好像说会考-List-的-Reverse" class="headerlink" title="(考点！！)List.reverse 教授好像说会考 List 的 Reverse ~~"></a>(考点！！)List.reverse 教授好像说会考 List 的 Reverse ~~</h3><p>分别利用 dropLeft 和 dropRight 来编写 reverse函数：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">reverse</span></span>[<span class="type">A</span>](as: <span class="type">List</span>[<span class="type">A</span>]): <span class="type">List</span>[<span class="type">A</span>] = &#123;</div><div class="line">	foldLeft(as, <span class="type">List</span>.empty[<span class="type">A</span>])((acc,a) =&gt; <span class="type">Cons</span>(a,acc))</div><div class="line">或者</div><div class="line">	foldLeft(as, <span class="type">Nil</span>:<span class="type">List</span>[<span class="type">A</span>])((acc,a)=&gt;<span class="type">Cons</span>(a,acc))</div><div class="line">实际：</div><div class="line">	foldLeft(as,<span class="type">Nil</span>:<span class="type">List</span>[<span class="type">A</span>])((a,acc)=&gt; acc::a )</div><div class="line">或者</div><div class="line">	foldLeft(as,<span class="type">Nil</span>:<span class="type">List</span>[<span class="type">A</span>])((acc,b) =&gt; append(b::<span class="type">Nil</span>,acc))</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">reverse</span></span>[<span class="type">A</span>](as:<span class="type">List</span>[<span class="type">A</span>]):<span class="type">List</span>[<span class="type">A</span>]= &#123;</div><div class="line">	foldRight(as,<span class="type">List</span>.empty[<span class="type">A</span>])((a,b)=&gt;append(b,<span class="type">Cons</span>(a,<span class="type">Nil</span>)))</div><div class="line">	实际：</div><div class="line">	foldRight(as,<span class="type">Nil</span>:<span class="type">List</span>[<span class="type">A</span>])((a,b)=&gt;append(b,a::<span class="type">Nil</span>))</div><div class="line">	或者：</div><div class="line">	</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>拆开 foldLeft和foldRight 版本的reverse<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">reverse-foldLeft(<span class="type">List</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>)) =</div><div class="line">foldLeft(list(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>),<span class="type">Nil</span>)((a,acc)=&gt; acc::a)=</div><div class="line">								(<span class="type">Nil</span>,<span class="number">1</span>)=&gt; <span class="number">1</span>::<span class="type">Nil</span> </div><div class="line">foldLeft(<span class="type">List</span>(<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>),<span class="number">1</span>::<span class="type">Nil</span>) =  </div><div class="line">								(<span class="number">1</span>::<span class="type">Nil</span>,<span class="number">2</span>) =&gt; <span class="number">2</span>::<span class="number">1</span>::<span class="type">Nil</span> </div><div class="line">foldLeft(<span class="type">List</span>(<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>),<span class="number">2</span>::<span class="number">1</span>::<span class="type">Nil</span>) = </div><div class="line">								(<span class="number">2</span>::<span class="number">1</span>::<span class="type">Nil</span>,<span class="number">3</span>) =&gt; <span class="number">3</span>::<span class="number">2</span>::<span class="number">1</span>::<span class="type">Nil</span></div><div class="line">...</div><div class="line"><span class="number">5</span>::<span class="number">4</span>::<span class="number">3</span>::<span class="number">2</span>::<span class="number">1</span>::<span class="type">Nil</span></div></pre></td></tr></table></figure></p>
<hr>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">reverse-foldRight(<span class="type">List</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>)) = </div><div class="line">foldRight(<span class="type">List</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>),<span class="type">Nil</span>)((a,b)=&gt;append(b,a::<span class="type">Nil</span>))</div><div class="line">append(floldRight(<span class="number">2</span>::<span class="number">3</span>::<span class="type">Nil</span>,<span class="type">Nil</span>),<span class="number">1</span>::<span class="type">Nil</span>)</div><div class="line">append(append(foldRight(<span class="number">3</span>::<span class="type">Nil</span>,<span class="type">Nil</span>),<span class="number">2</span>::<span class="type">Nil</span>),<span class="number">1</span>::<span class="type">Nil</span>)</div><div class="line">append(append(append(<span class="type">Nil</span>,<span class="number">3</span>::<span class="type">Nil</span>),<span class="number">2</span>::<span class="type">Nil</span>),<span class="number">1</span>::<span class="type">Nil</span>)</div><div class="line"><span class="number">3</span>::<span class="number">2</span>::<span class="number">1</span>::<span class="type">Nil</span></div></pre></td></tr></table></figure>
<p>思路：<br>利用foldRight和foldLeft的 原理和性质。<br>Left呢就是利用第一个元素和初始值进行计算然后带入到第二个元素计算中的初始值中，迭代计算。<br>Right呢就是 先不进行运算，先迭代到最底层然后从最后一个元素和初始值进行运算在返回来的这么一个过程。</p>
<h3 id="匿名函数的下划线注释-Underscore-notation-for-anonymous-functions"><a href="#匿名函数的下划线注释-Underscore-notation-for-anonymous-functions" class="headerlink" title="匿名函数的下划线注释(Underscore notation for anonymous functions)"></a>匿名函数的下划线注释(Underscore notation for anonymous functions)</h3><p>匿名函数(x,y) =&gt; x+ y 可以写成 <em> + </em> ，在 x 和 y 的类型可以被Scala 推测出的环境下。 这个非常实用，在case里面速写的时候，条件：在函数body中 参数只被提到一次的时候。在匿名函数中的每个下划线 像 <em> + </em> 引入了一种新的函数参数和参照它。参数以 从左至右的顺序被介绍。例如 x, y都只用了一次，顺序是 x, y 所以 可以 <em>, </em>来替代<br>下面有一些例子：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">_ + _         (x, y)	=&gt; x + y</div><div class="line">_ * 2         x      	=&gt; x * 2</div><div class="line">_.head        xs     	=&gt; xs.head</div><div class="line">_ drop _     	(xs, n) =&gt; xs.drop(n) </div><div class="line">_.drop(_)也可以</div></pre></td></tr></table></figure>
<p>请明智的使用这个语法。在表达式中这个语法的意义像 foo(<em> , g(List(</em> + 1), _ ))可能不会很清楚。关于这些 基于下划线的 匿名函数的 scope 有严格的 规则，在Scala 细则里面，除非你必须使用它，我们建议使用普通的参数命名规范。</p>
<h3 id="考点！！-List-flatten"><a href="#考点！！-List-flatten" class="headerlink" title="(考点！！)List.flatten"></a>(考点！！)List.flatten</h3><p>flatten函数就是把List(List(1,2,3), List(“a”,”b”,”c”),List(a,b,c))摊开了变成一个LIst(1,2,3,”a”,”b”,”c”,a,b,c)……<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">flatten</span></span>[<span class="type">A</span>](ffa: <span class="type">List</span>[<span class="type">List</span>[<span class="type">A</span>]]):<span class="type">List</span>[<span class="type">A</span>] = ffa <span class="keyword">match</span>&#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(h,t) =&gt; append(h, flatten(t))</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; <span class="type">Nil</span></div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">flatten</span></span>[<span class="type">A</span>](ffa: <span class="type">List</span>[<span class="type">List</span>[<span class="type">A</span>]]):<span class="type">List</span>[<span class="type">A</span>] =&#123;</div><div class="line">	foldLeft(ffa,<span class="type">List</span>.empty[<span class="type">A</span>])(append(_,_))</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<h3 id="考点！！-List-join"><a href="#考点！！-List-join" class="headerlink" title="(考点！！)List.join"></a>(考点！！)List.join</h3><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">join</span></span>[<span class="type">A</span>](ffa:<span class="type">List</span>[<span class="type">List</span>[<span class="type">A</span>]]):<span class="type">List</span>[<span class="type">A</span>] = &#123;</div><div class="line">	foldRight(ffa,<span class="type">List</span>.empty[<span class="type">A</span>])(append(_,_))</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="考点！！-Map"><a href="#考点！！-Map" class="headerlink" title="(考点！！)Map"></a>(考点！！)Map</h3><p>引子：想要在list 中的每个元素都➕1 怎么写？</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">incOne</span></span>(as:<span class="type">List</span>[<span class="type">Int</span>]):<span class="type">List</span>[<span class="type">Int</span>] = as <span class="keyword">match</span>&#123;</div><div class="line">	<span class="keyword">case</span> h::t =&gt; h+<span class="number">1</span>::incOne(t)</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; <span class="type">Nil</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>implicit class 是啥？</p>
<p>List[Double] -&gt; List[String]<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">doubleToString</span></span>(as:<span class="type">List</span>[<span class="type">Double</span>]):<span class="type">List</span>[<span class="type">String</span>] = as <span class="keyword">match</span>&#123;</div><div class="line">	<span class="keyword">case</span> h::t =&gt; h.toString::doubleToString(t)</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; <span class="type">Nil</span></div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>仔细观察这两个函数 发没发现 共同点：他们都没有改变原有List 的结构，只是单纯的改变了List 中 每一个元素的 值或者属性。这个跟foldright或者foldleft不太一样，fold系列改变了 List 的结构，拆开表格之后进行了这那那这的操作。</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">map</span></span>[<span class="type">A</span>,<span class="type">B</span>](fa:<span class="type">List</span>[<span class="type">A</span>])(f:<span class="type">A</span> =&gt; <span class="type">B</span>): <span class="type">List</span>[<span class="type">B</span>] = fa <span class="keyword">match</span> &#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(h,t) =&gt; f(h)::map(t)(f)</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; <span class="type">Nil</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">map2</span></span>[<span class="type">A</span>,<span class="type">B</span>](as:<span class="type">List</span>[<span class="type">A</span>])(f:<span class="type">A</span> =&gt; <span class="type">B</span>): <span class="type">List</span>[<span class="type">B</span>] = </div><div class="line">foldRight(as,<span class="type">List</span>.empty[<span class="type">B</span>])((a,acc)=&gt; f(a)::acc )</div><div class="line">或者：</div><div class="line">foldLeft(as,<span class="type">Nil</span>:<span class="type">List</span>[<span class="type">B</span>])((acc,a)=&gt; append(acc,f(a)::<span class="type">Nil</span>) )</div></pre></td></tr></table></figure>
<p>这里再说一嘴，foldRight 和 foldLeft是 scala里面 很重要的两个函数，它俩啥都能做。会考哦~~</p>
<p>那究竟什么是 map ，而map 为什么在scala中这么重要呢？<br>map 有两个输入，一个是 List 一个是 函数 f ， 他把list 中的每一个元素进行了f函数的处理之后 返回 这个原来的List。但是要说的是，原有的List 大结构可能不变，但是多少会变，比如<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">scala&gt; map(List(1,2,3))((x=&gt;x match&#123;case 3 =&gt; List(&apos;a&apos;,&apos;b&apos;) case _ =&gt; x*2&#125;))</div><div class="line">res57: List[Any] = List(2, 4, List(a, b))</div></pre></td></tr></table></figure></p>
<p>这个例子输入的List类型是List[Int] 但是出来之后变成List[Any]了，只是结构还是三个元素这个不变而已。</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">object</span> <span class="title">demo</span></span>&#123;</div><div class="line">	<span class="keyword">val</span> as = <span class="type">List</span>(<span class="number">1</span>,<span class="number">2</span>)</div><div class="line">	<span class="keyword">val</span> bs = <span class="type">List</span>(<span class="number">3</span>,<span class="number">4</span>)</div><div class="line">	</div><div class="line">	<span class="keyword">for</span>&#123;</div><div class="line">		a &lt;- as</div><div class="line">		b &lt;- bs</div><div class="line">	&#125;<span class="keyword">yield</span> (a,b)</div><div class="line">buxing 必须有 flatmap 和 map 类型</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>yield</code>是什么呢？yield 是跟在for 循环后面常常使用的一个关键字，然后他会把for中的 项记载下来在循环结束之后返回，类型和输入的类型是一样的。</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">flatMap</span></span>[<span class="type">A</span>,<span class="type">B</span>](as:<span class="type">List</span>[<span class="type">A</span>])(f: <span class="type">A</span> =&gt; <span class="type">List</span>[<span class="type">B</span>]): <span class="type">List</span>[<span class="type">B</span>] = as <span class="keyword">match</span> &#123;</div><div class="line">	<span class="keyword">case</span> <span class="type">Cons</span>(h,t) =&gt; append(f(h),flatMap(t)(f))</div><div class="line">	<span class="keyword">case</span> <span class="type">Nil</span> =&gt; <span class="type">Nil</span> </div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">flatMap2</span></span>[<span class="type">A</span>,<span class="type">B</span>](as:<span class="type">List</span>[<span class="type">A</span>])(f: <span class="type">A</span> =&gt; <span class="type">List</span>[<span class="type">B</span>]): <span class="type">List</span>[<span class="type">B</span>] =</div><div class="line">	foldRight(as,<span class="type">List</span>.empty[<span class="type">B</span>])((a,acc)=&gt;append(f(a),acc)) </div><div class="line">	或者：</div><div class="line">	foldLeft(as,<span class="type">List</span>.empty[<span class="type">B</span>])((acc,a)=&gt;append(acc,f(a)))</div></pre></td></tr></table></figure>
<p>其实哦，flatMap 和 Map 基本一样，唯一的不一样就是 它把Map 给 flatten了，也就是把里面的嵌套List结构都打散，变成了一个List。</p>
<p>在试图用 foldRight 和 foldLeft重写的时候 你要知道的是，这里面类型最最重要。<br><strong>思路：</strong></p>
<ul>
<li>首先 目标是：把元素里的每个元素都经过 f 函数变换，然后用append函数 将 List 变为一个，而没有嵌套List结构。所以 foldRight 和 foldLeft函数都符合范围。</li>
<li>其次我们思考格式匹配：<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">flatMap2</span></span>[<span class="type">A</span>,<span class="type">B</span>](as:<span class="type">List</span>[<span class="type">A</span>])(f: <span class="type">A</span> =&gt; <span class="type">List</span>[<span class="type">B</span>]): <span class="type">List</span>[<span class="type">B</span>] =</div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">foldRight</span></span>[<span class="type">A</span>,<span class="type">B</span>](as: <span class="type">List</span>[<span class="type">A</span>], z: <span class="type">B</span>)(f: (<span class="type">A</span>,<span class="type">B</span>) =&gt; <span class="type">B</span>) :<span class="type">B</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">foldLeft</span></span>[<span class="type">A</span>,<span class="type">B</span>](as:<span class="type">List</span>[<span class="type">A</span>],z:<span class="type">B</span>)(f :(<span class="type">B</span>,<span class="type">A</span>) =&gt; <span class="type">B</span>):<span class="type">B</span></div></pre></td></tr></table></figure>
</li>
</ul>
<p>因为我们要使用这两个函数，那么必须知道这两个函数的 参数类型和返回值类型，哇塞，能想到这个就已经算是具备一定编程思想的银了哎。<br>那不论foldRight还是foldLeft 第一个参数是不需要思考的 一样的，都是as，而且初始值 是 Nil  也没有错。 所以 ：<br><code>foldRight(as,List.empty[B])</code> 或者：<br><code>foldLeft(as,List.empty[B])</code><br>然后，我们思考 f 操作，foldRight的 f : (A,B) =&gt;B 那么我们希望append(f(第一个元素），后面的List ) 是结果变成：append(1,append(2,append(3,Nil)))这种。所以要<br><code>foldRight(as,List.empty[B])((a,acc)=&gt;append(f(a),acc))</code><br>接下来思考 foldLeft的 f 操作 : f : (B,A)=&gt;B 那么就是 Nil 作为 f 的第一参数，和 f (List 中的 第一个元素) 做 append操作，<br><code>foldLeft(as,List.empty[B])((acc,a)=&gt;append(acc,f(a)))</code><br>但是要保持元素和Nil 的顺序，但是append 有着这么一个特性，append(Nil,a2) = a2,所以这里就算 append (Nil, f(a))也没有关系，还是f(a)，<br>但是编程的时候 想的好复杂，left right 的内部逻辑还思考了很多，但是其实不需要思考，调用函数的时候，不许要考虑调用的函数的内部逻辑，只要参数类型对了，你选择的函数对了，就不要考虑太多了。</p>
<hr>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">map2</span></span>[<span class="type">A</span>,<span class="type">B</span>](as:<span class="type">List</span>[<span class="type">A</span>])(f:<span class="type">A</span> =&gt; <span class="type">B</span>): <span class="type">List</span>[<span class="type">B</span>] = </div><div class="line">	foldRight(as,<span class="type">List</span>.empty[<span class="type">B</span>])((a,acc)=&gt; f(a)::acc )</div><div class="line">	或者：</div><div class="line">	foldLeft(as,<span class="type">Nil</span>:<span class="type">List</span>[<span class="type">B</span>])((acc,a)=&gt; append(acc,f(a)::<span class="type">Nil</span>) )</div><div class="line">-----------------------------------------------------------</div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">flatMap2</span></span>[<span class="type">A</span>,<span class="type">B</span>](as:<span class="type">List</span>[<span class="type">A</span>])(f: <span class="type">A</span> =&gt; <span class="type">List</span>[<span class="type">B</span>]): <span class="type">List</span>[<span class="type">B</span>] =</div><div class="line">	foldRight(as,<span class="type">List</span>.empty[<span class="type">B</span>])((a,acc)=&gt;append(f(a),acc)) </div><div class="line">	或者：</div><div class="line">	foldLeft(as,<span class="type">List</span>.empty[<span class="type">B</span>])((acc,a)=&gt;append(acc,f(a)))</div></pre></td></tr></table></figure>
<p>在利用 foldRight 和 foldLeft 编写 map 和 flatMap的时候又多了一些感悟，这种感悟是一种感觉，不是简单地看规则就有的感觉。</p>
<h3 id="f-操作"><a href="#f-操作" class="headerlink" title="f 操作"></a>f 操作</h3><p>先看 map 和 flatMap的 f 操作，map是 A=&gt;B 也就是 list中的A类型元素经过 f 操作 生成 B类型的结果，注意这里不是生成了List 类型 而是B类型。<br>而flatMap的 f 操作生成的是 A=&gt;List[B] 元素类型为B的List类型，他们两个产物不太一样。</p>
<p>这一不同直接影响到了 body 的编写，因为 foldRight 和 foldLeft 要求的f 操作的类型分别是 (A,B)=&gt;B 和 (B,A)=&gt;B<br>那么看好了，<br>map：        <code>foldRight(as,List.empty[B])((a,acc)=&gt; f(a)::acc )</code><br>flatMap： <code>foldRight(as,List.empty[B])((a,acc)=&gt;append(f(a),acc))</code><br>这里面 (a,acc) 分别代表的是 (List中的每一个元素(A类型), Nil 和 迭代返回的B类型的 结果)。所以(a,acc)=&gt; f(a)::acc   的 类型检测就是 (A,B)=&gt; B::B 而从<code>List.empty[B]或者Nil:List[B]</code>这段代码系统就可以检测到 foldRight 的B类型是 List[B]，所以 B::B 返回一个List[B] 类型没啥问题，或者 B::List[B] 这种也是 返回 LIst[B]那么这有回到了第一节课的时候，有点脑子混乱，B类型和List[B]类性有点乱。而flatMap则不可以直接 f(a)::acc而是必须 append(f(a),acc)因为多了flaten的过程。</p>
<p>map:   <code>foldLeft(as,Nil:List[B])((acc,a)=&gt; append(acc,f(a)::Nil) )</code><br>flatMap: <code>foldLeft(as,List.empty[B])((acc,a)=&gt;append(acc,f(a)))</code><br>foldLeft的 f 操作的类型是 (B,A)=&gt;B , 所以 后面的那个a 才是 list中的元素。所以要 f(a)。 然后为什么要 f(a)::Nil 因为append要求 添加List[A]和 List[B]。而 f(a)返回的是 B类型的参数，必须加上NIl 编程 list[B]类型的才可以运行append。<br>要切记的是 Cons(List(a),List(b)) 和 append(List(a),List(b))是不一样的哦。</p>
<hr>
<p>莫纳德 拥有 flatmap 和map 。<br>那什么是 莫纳德？</p>
<p>学C++ 和 C 学 指针的时候最难<br>函数式方法中 莫纳德最难。。。</p>
<p>berrito？？？</p>
<hr>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">flatMap</span></span>[<span class="type">A</span>,<span class="type">B</span>](as:<span class="type">List</span>[<span class="type">A</span>])(f: <span class="type">A</span> =&gt; <span class="type">List</span>[<span class="type">B</span>]): <span class="type">List</span>[<span class="type">B</span>] = &#123;</div><div class="line">	flatten(map(as)(f)) </div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>flatmap就是先mapping 然后在flatting ~~</p>
<hr>
<h3 id="List-pure"><a href="#List-pure" class="headerlink" title="List.pure"></a><strong>List.pure</strong></h3><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">pure</span></span>[<span class="type">A</span>](a: <span class="type">A</span>): <span class="type">List</span>[<span class="type">A</span>] = <span class="type">List</span>(a)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">filter</span></span>[<span class="type">A</span>](as: <span class="type">List</span>[<span class="type">A</span>])(f: <span class="type">A</span> =&gt; <span class="type">Boolean</span>):<span class="type">List</span>[<span class="type">A</span>] = &#123;</div><div class="line">	flatMap(as)(a =&gt; <span class="keyword">if</span>(f(a)) <span class="type">List</span>(a) <span class="keyword">else</span> <span class="type">Nil</span>)</div><div class="line">	flatMap(as)(a =&gt; <span class="keyword">if</span>(f(a)) pure(a) <span class="keyword">else</span> <span class="type">Nil</span>)</div><div class="line">	因为这里用的是参数 <span class="type">LIst</span> 以后的话不一定参数类型就是<span class="type">LIst</span>类型的。</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<hr>
<h2 id="3-5-Trees-树"><a href="#3-5-Trees-树" class="headerlink" title="3.5 Trees (树)"></a>3.5 Trees (树)</h2><h2 id="3-6-Summary-总结"><a href="#3-6-Summary-总结" class="headerlink" title="3.6 Summary(总结)"></a>3.6 Summary(总结)</h2>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;#Scala/Chapter3#&lt;/p&gt;
&lt;h1 id=&quot;Chapter3-Functional-data-structures-函数式数据结构&quot;&gt;&lt;a href=&quot;#Chapter3-Functional-data-structures-函数式数据结构&quot; class=&quot;h
    
    </summary>
    
      <category term="Functional programming,Scala" scheme="http://www.sweatbuffer.com/categories/Functional-programming-Scala/"/>
    
    
      <category term="Functional programming" scheme="http://www.sweatbuffer.com/tags/Functional-programming/"/>
    
      <category term="Scala" scheme="http://www.sweatbuffer.com/tags/Scala/"/>
    
  </entry>
  
  <entry>
    <title>Functional programming in Scala(一)</title>
    <link href="http://www.sweatbuffer.com/2017/04/24/title:%20Functional%20programming%20in%20Scala(%E4%B8%80)/"/>
    <id>http://www.sweatbuffer.com/2017/04/24/title: Functional programming in Scala(一)/</id>
    <published>2017-04-24T11:53:18.000Z</published>
    <updated>2017-04-28T12:46:26.000Z</updated>
    
    <content type="html"><![CDATA[<p>#Scala/Chapter1#</p>
<h1 id="What-is-a-pure-function"><a href="#What-is-a-pure-function" class="headerlink" title="What is a pure function"></a>What is a pure function</h1><p>Pure function is one that lacks side effects.<br>what is side effects?</p>
<ul>
<li>修改一个变量</li>
<li>当场修改一个数据结构</li>
<li>对对象设置领域</li>
<li>抛出异常和处理error</li>
<li>命令提示符中打印，读取用户输入</li>
<li>读写文件</li>
<li>画图</li>
<li>连接server等~~</li>
</ul>
<p>用一句话说 一个函数除了根据我们的输入值计算结果之外不做任何我们可以观察得到的行为，那么可以基本看为纯粹函数，prue function。</p>
<h2 id="Referential-Transparency-RT"><a href="#Referential-Transparency-RT" class="headerlink" title="Referential Transparency(RT)"></a>Referential Transparency(RT)</h2><p>referential transparency 也叫 引用性透明： referential Transparency不只是 function的性质，也是 expressions的性质：在任何的程序里面 表达式可以在不改变程序语义的情况下，用结果值，result 来替换表达式。</p>
<h2 id="Referential-transparency-and-purity"><a href="#Referential-transparency-and-purity" class="headerlink" title="Referential transparency and purity"></a>Referential transparency and purity</h2><p>An expression <code>e</code> is <em>referential transparent</em> if , for all programs <code>p</code>, all occurrences of <code>e</code> in <code>p</code>can be replaced by the result of evaluating <code>e</code> without affecting the meaning of <code>p</code>.<br>A function <code>f</code> is <em>pure</em> if the expression <code>f(x)</code>is referentially transparent for all referentially transparent <code>x</code>.  </p>
<h2 id="Substitution-model"><a href="#Substitution-model" class="headerlink" title="Substitution model"></a>Substitution model</h2><p>Referential transparency forces the invariant that everything a function does is represented by the <strong>~value~</strong> that it returns, according to the result type of the functions.<br>This constraint enables a simple and natural mode of reasoning about program evaluation called the <strong>~substitution model~</strong></p>
<p>在这样的规则下，我们的计算过程就是想是解代数方程。我们扩张表达式的所有的部分然后用他们的 参考对象 替换所有的变量，然后分解到最简式子。换句话说 RT 允许 方程式推理(equational reasoning )</p>
<h3 id="关于RT的个人的想法："><a href="#关于RT的个人的想法：" class="headerlink" title="关于RT的个人的想法："></a>关于RT的个人的想法：</h3><p>RT叫 referential transparency 引用性透明，相比较C 这种语言来说有着很大的不同。scala中 对一个变量调用他的一些方法，产生了一个新的结果，这个结果会给予一个新的空间，新的变量名字，之前引用的变量不发生任何变化。<br>为啥这样设计，因为要支持函数式编程，很符合递归的概念。</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">scala&gt; <span class="keyword">val</span> x= <span class="string">"Hello,world"</span></div><div class="line">x: <span class="type">String</span> = <span class="type">Hello</span>,world</div><div class="line"></div><div class="line">scala&gt; <span class="keyword">val</span> r1 = x.reverse</div><div class="line">r1: <span class="type">String</span> = dlrow,olleH</div><div class="line"></div><div class="line">scala&gt; <span class="keyword">var</span> r2 = x.reverse</div><div class="line">r2: <span class="type">String</span> = dlrow,olleH</div><div class="line"></div><div class="line">scala&gt; <span class="keyword">val</span> r1 = <span class="string">"Hello,world"</span>.reverse</div><div class="line">r1: <span class="type">String</span> = dlrow,olleH</div><div class="line"></div><div class="line">scala&gt; <span class="keyword">val</span> r2 = <span class="string">"Hello,world"</span>.reverse</div><div class="line">r2: <span class="type">String</span> = dlrow,olleH</div></pre></td></tr></table></figure>
<p>x 是 String 对象，reverse 是 String 类的 成员方法<br>这个例子就是 x 调用了 reverse之后 并没有改变x自身的值，所以再次调用reverse方法 还是一样的结果。就完全可以用 x 的值”Hello,world”来替代之前式子中的x。</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">scala&gt; <span class="keyword">val</span> x = <span class="keyword">new</span> <span class="type">StringBuilder</span>(<span class="string">"Hello"</span>)</div><div class="line">x: <span class="type">StringBuilder</span> = <span class="type">Hello</span></div><div class="line"></div><div class="line">scala&gt; <span class="keyword">val</span> y = x.append(<span class="string">",world"</span>)</div><div class="line">y: <span class="type">StringBuilder</span> = <span class="type">Hello</span>,world</div><div class="line"></div><div class="line">scala&gt; <span class="keyword">val</span> r1 = y.toString</div><div class="line">r1: <span class="type">String</span> = <span class="type">Hello</span>,world</div><div class="line"></div><div class="line">scala&gt; <span class="keyword">val</span> r2 = y.toString</div><div class="line">r2: <span class="type">String</span> = <span class="type">Hello</span>,world</div><div class="line"></div><div class="line">scala&gt; <span class="keyword">val</span> r3 = x.append(<span class="string">",world"</span>).toString</div><div class="line">r3: <span class="type">String</span> = <span class="type">Hello</span>,world,world</div><div class="line"></div><div class="line">scala&gt; x</div><div class="line">res102: <span class="type">StringBuilder</span> = <span class="type">Hello</span>,world,world</div></pre></td></tr></table></figure>
<p>这里的x 是 Stringbuilder 对象 ， append 是 Stringbuilder 类的 成员方法。<br>这里 x 调用了一次 append 方法之后，自身的值改变了，所以在第二次调用append 的时候 变成了 Hello，world，world。而 String 对象的 toString方法，没有啥变化，调用了两次也没啥问题。所以Stringbuilder.append不是一个pure function 不是存粹方法。所以side effect 使得程序推理编的很困难。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;#Scala/Chapter1#&lt;/p&gt;
&lt;h1 id=&quot;What-is-a-pure-function&quot;&gt;&lt;a href=&quot;#What-is-a-pure-function&quot; class=&quot;headerlink&quot; title=&quot;What is a pure functio
    
    </summary>
    
      <category term="Functional programming,Scala" scheme="http://www.sweatbuffer.com/categories/Functional-programming-Scala/"/>
    
    
      <category term="Functional programming" scheme="http://www.sweatbuffer.com/tags/Functional-programming/"/>
    
      <category term="Scala" scheme="http://www.sweatbuffer.com/tags/Scala/"/>
    
  </entry>
  
  <entry>
    <title>Functional programming in Scala(0)</title>
    <link href="http://www.sweatbuffer.com/2017/04/15/scala0/"/>
    <id>http://www.sweatbuffer.com/2017/04/15/scala0/</id>
    <published>2017-04-15T05:48:45.000Z</published>
    <updated>2017-05-09T13:01:53.000Z</updated>
    
    <content type="html"><![CDATA[<p>#Scala/Chapter0#</p>
<h1 id="Lambda-Calculus"><a href="#Lambda-Calculus" class="headerlink" title="Lambda Calculus"></a>Lambda Calculus</h1><p>lambda之所有这么重要，是因为它具有“二象性”：它既可以被看作一种简单地程序设计语言，用于描述计算过程；也可以被看做一个数学对象，用于推导证明一些命题。</p>
<h2 id="Function-函数"><a href="#Function-函数" class="headerlink" title="Function (函数)"></a>Function (函数)</h2><ul>
<li>Black Box</li>
<li>Pure<br>我们把函数看成一个Black Box，<code>x -&gt; f -&gt; y</code> 就是只有一个输入和对于同一个输入只产生唯一一种结果。也就是说输出 y 只依赖于 输入 x ，并无其他任何因素可以影响函数的输出结果 y。</li>
</ul>
<hr>
<h2 id="Functional-Model-of-Computation"><a href="#Functional-Model-of-Computation" class="headerlink" title="Functional Model of Computation"></a>Functional Model of Computation</h2><ul>
<li>Express computation based on <ul>
<li>(anonymous ) function ~<strong>abstraction</strong>~ and </li>
<li>function ~<strong>application</strong>~ via <strong>binding</strong> and <strong>substitution</strong><br>function abstraction 函数抽象指的是 用lambda表示的式子<br>function application 指的是lambda式子右边的值带入左边的lambda式子里面替换 式子的 body 里面 与 变量绑定的值。</li>
</ul>
</li>
<li>Equivalent to <strong>state-based</strong> Turing Machine by Alan Turing  </li>
</ul>
<hr>
<h2 id="Syntax"><a href="#Syntax" class="headerlink" title="Syntax"></a>Syntax</h2><p>lambda expressions are :</p>
<ul>
<li>E = ID             for example : x,y,z,…..variables ID</li>
<li>E = /ID. M      the abstraction symbols lambda ‘/’ and dot ‘.’</li>
<li>E = (MN)        parentheses ()</li>
<li>E = (E)<br>pure lambda calculus does not define constants, operators, etc.</li>
</ul>
<hr>
<h2 id="便于理解的例子-amp-Currying"><a href="#便于理解的例子-amp-Currying" class="headerlink" title="便于理解的例子 &amp; Currying"></a>便于理解的例子 &amp; Currying</h2><p>平方和函数：<code>f(x,y) = x*x + y*y  |  f(3,4) = 3*3 + 4*4</code><br>映射：  <code>(x,y) -&gt; x*x +y*y  | ((x,y) -&gt; x*x +y*y)(3,4) = 3*3 + 4*4</code><br>变一下形式，编程单参数函数:<br>        <code>(x -&gt; (y -&gt; x*x + y*y))</code> 什么意思呢，把x 映射为另外一个y的映射~ <code>(x -&gt; (y -&gt; x*x + y*y))(3) = (y -&gt; 3*3 + y*y)</code><br><code>(y -&gt; 3*3 + y*y)(4) = 3*3 + 4*4</code><br>这样子就把 <code>f(x,y) 变成了 f(x)(y)</code> 用类似的方法把多个参数的函数编程单个参数的函数的高阶函数，这个转换叫做 currying。<br>更易于理解的看一下：<br><code>def f(x:Int,y:Int):Int = x*x +y*y</code>变成了：<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">f</span></span>(x:<span class="type">Int</span>):<span class="type">Int</span> = &#123;</div><div class="line">	<span class="function"><span class="keyword">def</span> <span class="title">f</span></span>(y:<span class="type">Int</span>):<span class="type">Int</span> = x*x + y*y</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>以上都是我个人理解，代码不准确，想表达某一个意思呢，我也不知道怎么说好，第一 上面的应该是匿名函数，我写成了有名字的函数呢。然后 。。。</p>
<p>为什么要转换？意义是什么？</p>
<hr>
<h2 id="Notation-Simplification-符号简化"><a href="#Notation-Simplification-符号简化" class="headerlink" title="Notation Simplification(符号简化)"></a>Notation Simplification(符号简化)</h2><ul>
<li>lambda 式子中的最外层的括号可以摘掉 例如 (/x.x) -&gt; /x.x </li>
<li>lambda 式子是左结合的，所以是左面优先的 例如 (((MN)P)Q) -&gt; MNPQ</li>
</ul>
<h3 id="Disambiguation-Rules-不暧昧规则"><a href="#Disambiguation-Rules-不暧昧规则" class="headerlink" title="Disambiguation Rules(不暧昧规则)"></a>Disambiguation Rules(不暧昧规则)</h3><ul>
<li>Application are assumed to be left associative : <ul>
<li>M N P my be written instead of ((MN)P)</li>
</ul>
</li>
<li>The body of an abstraction extends as far as possible: <ul>
<li>/x.MN are not (/x.M)N , they are different </li>
<li>(/x./y.yx)ab != /x./y.yxab </li>
<li>((/x./y.yx)ab)   and  (/x./y.(yxab)) </li>
</ul>
</li>
<li>/x.AB means /x.(AB) is an function abstraction while </li>
<li>(/x.A)B is an function application means B is a parameter of<br>the function (/x.A)</li>
</ul>
<hr>
<h2 id="Abstraction-Syntax-Tree"><a href="#Abstraction-Syntax-Tree" class="headerlink" title="Abstraction Syntax Tree"></a>Abstraction Syntax Tree</h2><p>lambda: abstraction operator<br>apply: application operator</p>
<ul>
<li>the right subtree of the apply node is the actual argument</li>
<li>the left subtree of the apply node is (with a lambda at its root) the function</li>
<li>the left child of the lambda is the <strong>_</strong> parameter.</li>
<li>the right child of the lambda is the function body. </li>
</ul>
<hr>
<h2 id="Problems-with-the-naive-rewriting-rule"><a href="#Problems-with-the-naive-rewriting-rule" class="headerlink" title="Problems with the naive rewriting rule"></a>Problems with the naive rewriting rule</h2><p>Simple rule for rewriting <code>(/x.M)N</code>means “replace all occurrences of x in M with N”. However , there are two problems with this rule</p>
<ul>
<li><strong>“Scope escape” problem</strong></li>
<li><strong>“Capture” or “name clash” problem</strong></li>
</ul>
<p><strong>Problem 1 : Scope escape :</strong><br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"> (/x.(x + ((/x.x+<span class="number">1</span>)<span class="number">3</span>)))<span class="number">2</span> </div><div class="line">=&gt; (/x.(x+(<span class="number">3</span>+<span class="number">1</span>)))<span class="number">2</span></div><div class="line">=&gt; (/x.(x+<span class="number">4</span>))<span class="number">2</span></div><div class="line">=&gt; (<span class="number">2</span>+<span class="number">4</span>) =&gt; <span class="number">6</span></div><div class="line">--------------------------------------------------------------</div><div class="line"> (/x.(x + ((/x.x+<span class="number">1</span>)<span class="number">3</span>)))<span class="number">2</span></div><div class="line">=&gt; (<span class="number">2</span>+ ((/x<span class="number">.2</span>+<span class="number">1</span>)<span class="number">3</span>)) )</div><div class="line">=&gt; (<span class="number">2</span>+ (<span class="number">2</span>+<span class="number">1</span>))</div><div class="line">=&gt; (<span class="number">2</span>+<span class="number">3</span>) =&gt; <span class="number">5</span></div></pre></td></tr></table></figure></p>
<p>也就是这里的 第一个x 绑定的是最外层的x 而 最内层的x 绑定的则是 内部的x 他俩绑定的值不一样所以 用最外层2 带入值的时候不可以 替换内部的呢，所以会出现问题。</p>
<p><strong>Problem 2 : Name clash :</strong><br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">((/x./y.x)y)z</div><div class="line">=&gt; (/y.y)z</div><div class="line">=&gt; z</div><div class="line">----------------</div><div class="line">((/x./a.x)y)z</div><div class="line">=&gt;(/a.y)z</div><div class="line">=&gt; y</div></pre></td></tr></table></figure></p>
<p>本来的y 和 /y 没有绑定关系的，但是在带入之后突然就有了关系，这样就造成了错误的绑定和错误的结果。</p>
<h2 id="Bound-amp-Free-Variables"><a href="#Bound-amp-Free-Variables" class="headerlink" title="Bound &amp; Free Variables"></a>Bound &amp; Free Variables</h2><ul>
<li>Bound Variable：a variable that is associated with some lambda</li>
<li>Free Variable：a variable that is not associated with any lambda</li>
<li>Intuitively , in lambda-expression M, variable x is bound if , in the AST, x is in the subtree of a lambda with left child x. 这句话换句话就是 如果 这个 x 是处于 lambda Scope 范围内的话 他就是被 lambda 绑定的变量，除非里面没有另一个 lambda x 式子。</li>
</ul>
<ol>
<li>FV(x) = {x}<br>In the expression x , variable x is free. 因为没有lambda 单独的x 当然是free</li>
<li>FV(M,N) = FV(M) U FV(N)<br>In the expression M N :<br>a. The free variables of M N are the union of two sets.<br>b. The bound variables of M N are also the union of two sets. </li>
<li>FV(/x.M) = FV(M) - {x} (除了x M中的自由变量都是自由的)<br>In the expression /x.M,<br>every x in M is bound;<br>Every variable y != x that is free in M is free in /x.M;<br>Every variable is bound in M is bound in /x.M.</li>
</ol>
<p>练习：<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">(/x. x(/y.xyzy)x )xy</div></pre></td></tr></table></figure></p>
<h3 id="Solution-of-the-Problem-1"><a href="#Solution-of-the-Problem-1" class="headerlink" title="Solution of the Problem 1 :"></a>Solution of the Problem 1 :</h3><p>Revised Rewriting Rule : To solve this problem ,given lambda expression<br>(/x.M)N “Replacing all occurrences of x that are free in M with N”<br><code>(/x. x + ((/x.x +1)3)) 2</code><br>这里的第一个 x 是 M 中的 free 变量，而 第二个里面的 x 则是在 M中有绑定值。所以我们可以在 application的 时候  用2 来替换 M中的 第一个free的 变量x 。这里的x 对于 M来说是 free 但是对于 lambda 表达式来说是 bounded。<br><code>(/x. x + ((/x.x +1)3)) 2 =&gt; 2+((/x.x +1)3)</code></p>
<h3 id="Solution-of-the-Problem-2"><a href="#Solution-of-the-Problem-2" class="headerlink" title="Solution of the Problem 2:"></a>Solution of the Problem 2:</h3><p>The variable y that is free in the argument to a lambda expression becomes bounded after rewriting , because it is put into the scope of a lambda expression with a formal parameter named y:<br><code>((/x./y.x)y)z</code>这里的外层的y 进入内层替换x 之后 就变得绑定了。所以引出了 阿尔法等式：</p>
<h2 id="a-equivalence-a-等价-amp-a-conversion-a-约定"><a href="#a-equivalence-a-等价-amp-a-conversion-a-约定" class="headerlink" title="a-equivalence (a 等价) &amp; a-conversion (a 约定)"></a>a-equivalence (a 等价) &amp; a-conversion (a 约定)</h2><p>The basic idea is that formal parameter names are unimportant ;so rename them as needed to avoid capture or name clash.<br><strong>a-conversion</strong> modifies expressions of the form <strong>/x.M</strong> to <strong>/z.M</strong><br>rename all the occurrences of x that are free in M to some other variable z that does not occur in M (and then /x is changed to /z).意思就是 M中的free的x 才是 /x.M 中和 lambda 绑定的x 而 M 中 bounded的 x 则是内部绑定的和外部的 lambda 没有绑定关系所以不能替换，所以 先把 外部的 /x. 替换成 /z.把 M中 free的 x 替换成z. 注意的是 z 不允许出现在 M中 反而产生别的问题。<br><code>/x./y.x+y</code>可以通过 a-reduces 到 <code>/z./y.z+y</code></p>
<h3 id="Renaming-Operation-a-conversion"><a href="#Renaming-Operation-a-conversion" class="headerlink" title="Renaming Operation (a-conversion)"></a>Renaming Operation (a-conversion)</h3><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="type">E</span>&#123;y/x&#125; 用 y 替换 x</div><div class="line">- x&#123;y/x&#125; = y</div><div class="line">- z&#123;y/x&#125; = z, <span class="keyword">if</span> z!= x</div><div class="line">- (<span class="type">M</span> <span class="type">N</span>)&#123;y/x&#125; = (<span class="type">M</span>&#123;y/x&#125;)(<span class="type">N</span>&#123;y/x&#125;)</div><div class="line">- (/x.<span class="type">E</span>)&#123;y/x&#125; = (/y.<span class="type">E</span>&#123;y/x&#125;) <span class="keyword">if</span> no y in <span class="type">E</span> </div><div class="line">- (/z.<span class="type">E</span>)&#123;y/x&#125; = (/z.<span class="type">E</span>&#123;y/x&#125;) <span class="keyword">if</span> z != x</div><div class="line">example :</div><div class="line">((/x.x(/y.xyzy)x) x y)&#123;bar/x&#125;</div><div class="line">----------------  - - </div><div class="line">		<span class="type">A</span> 		    <span class="type">B</span> <span class="type">C</span></div><div class="line">=&gt; (/x.x(/y.xyzy)x)&#123;bar/x&#125;(x)&#123;bar/x&#125;(y)&#123;bar/x&#125;</div><div class="line">=&gt; (/bar.(x(/y.xyzy)x)&#123;bar/x&#125;) bar y</div><div class="line">=&gt; (/bar.bar (/y.xyzy)&#123;bar/x&#125; bar) bar y</div><div class="line">=&gt; (/bar.bar (/y.bar yzy)bar) bar y</div></pre></td></tr></table></figure>
<h3 id="a-equivalence"><a href="#a-equivalence" class="headerlink" title="a-equivalence"></a>a-equivalence</h3><p>For all expressions E and all variables y that do not occur in E<br>            <code>/x.E =a /y.(E{y/x})</code></p>
<h2 id="Substitution-替换"><a href="#Substitution-替换" class="headerlink" title="Substitution (替换)"></a>Substitution (替换)</h2><p>substitution 的目的是把M中的自由变量x (也就是 受/x 约束的 x 替换成 N实现application)<br><code>(/x.+x1)2 -&gt; (+ 2 1)</code> replace a variable by a lambda expression </p>
<ul>
<li>E[ x -&gt; N ] ，when E and N are lambda expressions and x is a name.<figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">(/y./x.yx)(/z.xz)</div><div class="line">=&gt;(/x.yx)[y -&gt; /z.xz]</div><div class="line">=&gt;(/x.(/z.xz)x) =&gt; trouble! </div><div class="line">因为 /z.xz 中的 x 本来是 自由变量而在替换之后和里面的 /x 产生bound关系了，所以在替换前对于原来的式子使用 a-reduction! </div><div class="line">=&gt; (/w.(/z.xz)w)这样就没有多添加的关系了。</div></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="Substitution-Rule"><a href="#Substitution-Rule" class="headerlink" title="Substitution Rule"></a>Substitution Rule</h3><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="type">E</span>[x-&gt;<span class="type">N</span>]</div><div class="line"><span class="number">1.</span> x[x-&gt;<span class="type">N</span>] = <span class="type">N</span></div><div class="line"><span class="number">2.</span> y[x-&gt;<span class="type">N</span>] = y, <span class="keyword">if</span> x != y</div><div class="line"><span class="number">3.</span> (<span class="type">E1</span> <span class="type">E2</span>)[x-&gt;<span class="type">N</span>] = (<span class="type">E1</span>[x-&gt;<span class="type">N</span>])(<span class="type">E2</span>[x-&gt;<span class="type">N</span>])</div><div class="line"><span class="number">4.</span> (/x.<span class="type">E</span>)[x-&gt;<span class="type">N</span>] = (/x.<span class="type">E</span>) 里面不可能有 free 的 x ！！这个要想一下</div><div class="line"><span class="number">5.</span> (/y.<span class="type">E</span>)[x-&gt;<span class="type">N</span>] = (/y.<span class="type">E</span>[x-&gt;<span class="type">N</span>])when y!= x and y不属于<span class="type">FV</span>(<span class="type">N</span>)如果<span class="type">N</span>中存在free的 y 那么替换之后 会突然增加绑定关系</div><div class="line"><span class="number">6.</span> (/y.<span class="type">E</span>)[x-&gt;<span class="type">N</span>] = (/z.<span class="type">E</span>&#123;z/y&#125;[x-&gt;<span class="type">N</span>])when y != x and y 属于 <span class="type">FV</span>(<span class="type">N</span>) 								   and z != x and z 不属于 <span class="type">FV</span>(<span class="type">N</span>) </div><div class="line">sepecial : <span class="number">4</span>条 有点模糊哦，</div><div class="line">(/x.<span class="type">E</span>)[x-&gt;<span class="type">N</span>] 意味着 (/x./x.<span class="type">E</span>)(<span class="type">N</span>) 这种情况要带入<span class="type">N</span> 然后替换 /x.<span class="type">E</span> 中和 外部的/x 绑定的 x 但是 /x.<span class="type">E</span> 中肯定不可能存在和外部绑定的x 都被里面的/x所绑定了。所以  (/x./x.<span class="type">E</span>)(<span class="type">N</span>) = /x.<span class="type">E</span> 所以才有的 (/x.<span class="type">E</span>)[x-&gt;<span class="type">N</span>] = (/x.<span class="type">E</span>)</div></pre></td></tr></table></figure>
<p>Example :<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line">(/x.x)[x-&gt;foo] =&gt; /x.x  by (<span class="number">4</span>)</div><div class="line"></div><div class="line">(+<span class="number">1</span>x)[x-&gt;<span class="number">2</span>]</div><div class="line">=&gt; (+[x-&gt;<span class="number">2</span>] <span class="number">1</span>[x-&gt;<span class="number">2</span>] x[x-&gt;<span class="number">2</span>]) by(<span class="number">3</span>)</div><div class="line">=&gt; (+ <span class="number">1</span> <span class="number">2</span>) by (<span class="number">2</span>),(<span class="number">1</span>)</div><div class="line"></div><div class="line">--------------------------------------------------------------</div><div class="line">(/y./x.yx)(/z.xz)</div><div class="line">(/x.yx)[y-&gt;/z.xz]</div><div class="line">=&gt; (/w.yw)[y-&gt;/z.xz]  by(<span class="number">6</span>) since x 属于 <span class="type">FV</span>(/z.xz)</div><div class="line">=&gt; (/w.(yw)[y-&gt;/z.xz])   by (<span class="number">5</span>)</div><div class="line">=&gt; (/w.(y[y-&gt;/z.xz] w[y-&gt;/z.xz])) by (<span class="number">3</span>)</div><div class="line">=&gt; (/w.(/z.xz) w) by(<span class="number">1</span>),(<span class="number">2</span>)</div><div class="line">--------------------------------------------------------------</div><div class="line">(/x./y.(/f.fx)y)(fy)</div><div class="line">(/y.(/f.fx)y)[x-&gt;fy]</div><div class="line">=&gt; (/w.(/f.fx)w)[x-&gt;fy]  by(<span class="number">6</span>) since y 属于 <span class="type">FV</span>(fy)</div><div class="line">=&gt; (/w.(/f.fx)[x-&gt;fy]w[x-&gt;fy]) by(<span class="number">5</span>),(<span class="number">3</span>)</div><div class="line">=&gt; (/w.(/f.fx)&#123;f/z&#125;[x-&gt;fy] w) by(<span class="number">6</span>),(<span class="number">2</span>) since f 属于 <span class="type">FV</span>(fy)</div><div class="line">=&gt; (/w.(/z.zx)[x-&gt;fy] w )</div><div class="line">=&gt;  /w. (z(fy)) w </div><div class="line">--------------------------------------------------------------</div><div class="line">(/y./z.yz)(/z.xz)</div><div class="line">(/z.yz)[y-&gt;/z.xz]</div><div class="line">=&gt; (/z.(yz)[y-&gt;/z.xz])</div><div class="line">=&gt; (/z.(y[y-&gt;/z.xz] z[y-&gt;/z.xz]) )</div><div class="line">=&gt; /z.( (/z.xz) z )</div></pre></td></tr></table></figure></p>
<h2 id="Precise-Meaning-of-Rewriting-Beta-reduction"><a href="#Precise-Meaning-of-Rewriting-Beta-reduction" class="headerlink" title="Precise Meaning of Rewriting : Beta-reduction"></a>Precise Meaning of Rewriting : Beta-reduction</h2><p>进行Substitution 的过程叫做 B-reduction<br>(/x.M)N   -&gt; B   M[x -&gt; N]<br>左边的部分(/x.M)N 叫做 redex(可约式)<br>右边的部分 M[x -&gt; N] 叫做 contractum (缩减项)<br>中间的 -&gt; B 记号(notation)意味着 all free occurrences of x replaced with N in a way that avoids capture/Name clash .<br> 个人想法：这是种什么感觉呢 就是 比如一个f(x)(y) ，f(3)通过一次Beta-reduction 把x相关的都用 3 替代了。然后计算 y 部分的。或者说<br>(/x./y.E)N 然后通过B-reduction 把 跟 /x 相关的绑定变量都用N替代了。接下来就编程了只有一个参数y的函数了。</p>
<h3 id="Normal-Form-范式"><a href="#Normal-Form-范式" class="headerlink" title="Normal Form (范式)"></a>Normal Form (范式)</h3><p>A computation is finished when there are no more redexes.<br>A lambda expression without redexes is in normal form.<br>A lambda expression has a normal form iff there is some sequence of B-reduction that leads to a normal form. </p>
<p><strong>Ps</strong>: 不是所有的式子都可能 B-reduce到 Normal form ， 因为有些式子越约越长。。<br>如果你得到一个B范式，那么可以确定他是唯一的，不用担心因为规约顺序而导致不同的结果，换句话说 一个式子 不论怎么规约，只可能规约出唯一的一种范式。<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line">(/x.x)y </div><div class="line">=&gt; x[x-&gt;y]</div><div class="line">=&gt; y</div><div class="line">------------</div><div class="line">(/x.x(/x.x))(ur)</div><div class="line">=&gt;(x(/x.x))[x-&gt;ur]</div><div class="line">=&gt;x[x-&gt;ur](/x.x)[x-&gt;ur]</div><div class="line">=&gt;ur(/x.x)</div><div class="line">-----------------------</div><div class="line">(/x.y) ((/z.zz)(/w.w))</div><div class="line">------ ---------------</div><div class="line">  <span class="type">A</span>           <span class="type">B</span></div><div class="line">=&gt; (/x.y) (zz)[z-&gt;/w.w]</div><div class="line">=&gt; (/x.y) ((/w.w)(/w.w))</div><div class="line">=&gt; (/x.y) (w)[w-&gt;/w.w]</div><div class="line">=&gt; (/x.y) (/w.w)</div><div class="line">=&gt; (y)[x-&gt;/w.w]</div><div class="line">=&gt;  y</div><div class="line">另一种顺序的算法：</div><div class="line">(/x.y) ((/z.zz)(/w.w))</div><div class="line">------ ---------------</div><div class="line">  <span class="type">A</span>           <span class="type">B</span></div><div class="line">=&gt; (/x.y)[x-&gt;((/z.zz)(/w.w))]</div><div class="line">=&gt; y</div></pre></td></tr></table></figure></p>
<h2 id="Yita-Reduction"><a href="#Yita-Reduction" class="headerlink" title="Yita-Reduction"></a>Yita-Reduction</h2><p>if v is a variable ,  E is a lambda expression (denoting a function), and v has no free occurrence in E,<br>        /v.(Ev) =&gt;yita  E</p>
<p>/x.(sqr x) =&gt;yita sqr<br>/x.(add 5 x) =&gt;yita (add 5)</p>
<p>The yita-reduction rule can be used to justify the extensionality of functions; namely, if f(x) = g(x) for all x, then f = g.</p>
<p>理解的不多，就是比如说哦 (/x.fx)y=&gt;fy ,所以是不是 感觉到了 (/x.fx) = f 在某种意义上。但是如果 f 中存在着 x 的自由变量，那么意味着这个f 中的自由变量x 是和 外面的 /x 绑定的，那么就是说 f 会在 y 导入的时候发生变化的。那么久不一定相等了，所以才有的这么一个条件就是在 E 中不存在 v 的自由变量的时<br>候 /v.(Ev) =yita E </p>
<h2 id="deta-reduction"><a href="#deta-reduction" class="headerlink" title="deta-reduction"></a>deta-reduction</h2><p>if lambda calculus has predefined constants(that is , if it is not pure),rules associated with those predefined values and functions are called deta-rules.<br>for example:<br>    (add 3 5) =&gt;deta 8 ,<br>    (not ture)=&gt;deta flase.</p>
<h1 id="Pure-Lambda-Calculus"><a href="#Pure-Lambda-Calculus" class="headerlink" title="Pure Lambda Calculus"></a>Pure Lambda Calculus</h1><p>这里想说的核心内容就是： Booleans, integers, and (other data structures) can be entirely replaced by functions!!! </p>
<h2 id="Branch"><a href="#Branch" class="headerlink" title="Branch"></a>Branch</h2><p>if p then q else r can be thought as COND p q r </p>
<p>TRUE     x y -&gt; x<br>FALSE   x y -&gt; y<br>Then <code>COND = /p./q./r.p q r</code>where<br>TRUE  = <code>/x./y.x</code> FALSE = <code>/x./y.y</code><br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="type">COND</span> <span class="type">TRUE</span> a b 记住了lambda简化必须是左结合</div><div class="line">=&gt; (/p./q./r.pqr)(/x./y.x)ab</div><div class="line">=&gt; (/q./r.(/x./y.x)qr)ab</div><div class="line">=&gt; (/x./y.x)ab</div><div class="line">=&gt; a</div></pre></td></tr></table></figure></p>
<h2 id="Boolean-Logic"><a href="#Boolean-Logic" class="headerlink" title="Boolean Logic"></a>Boolean Logic</h2><p>TRUE     = /x./y.x<br>FALSE     = /x./y.y<br>AND    = /a./b. a b FALSE<br>OR         = /a./b. a TRUE b<br>NOT     = /a.a FALSE TRUE<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">and <span class="type">T</span> <span class="type">F</span></div><div class="line">(/a./b. a b (/x./y.y))(/x./y.x)(/x./y.y)</div><div class="line">=&gt; (/x./y.x)(/x./y.y)(/x./y.y)</div><div class="line">=&gt; (/y.(/x./y.y))(/x./y.y)</div><div class="line">=&gt; (/x./y.y)</div><div class="line">=&gt; <span class="type">F</span></div><div class="line">--------------------------------------------------------------</div><div class="line">not <span class="type">TRUE</span></div><div class="line">(/a.a <span class="type">FALSE</span> <span class="type">TRUE</span>)<span class="type">TURE</span></div><div class="line">=&gt; (<span class="type">TURE</span> <span class="type">FALSE</span> <span class="type">TRUE</span>)</div><div class="line">=&gt; <span class="type">FALSE</span></div></pre></td></tr></table></figure></p>
<h2 id="and-T-F"><a href="#and-T-F" class="headerlink" title="and T F"></a>and T F</h2><h2 id="not"><a href="#not" class="headerlink" title="not"></a>not</h2><h2 id="Church-s-Numerals"><a href="#Church-s-Numerals" class="headerlink" title="Church`s Numerals"></a>Church`s Numerals</h2><h2 id="Successor-Function"><a href="#Successor-Function" class="headerlink" title="Successor Function"></a>Successor Function</h2><h2 id="Addition"><a href="#Addition" class="headerlink" title="Addition"></a>Addition</h2><h2 id="Multiplication"><a href="#Multiplication" class="headerlink" title="Multiplication"></a>Multiplication</h2><h2 id="Turing-Complete"><a href="#Turing-Complete" class="headerlink" title="Turing Complete"></a>Turing Complete</h2><h2 id="Factorial"><a href="#Factorial" class="headerlink" title="Factorial"></a>Factorial</h2><h2 id="Y-Combinator"><a href="#Y-Combinator" class="headerlink" title="Y Combinator"></a>Y Combinator</h2><h2 id="Recursion"><a href="#Recursion" class="headerlink" title="Recursion"></a>Recursion</h2>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;#Scala/Chapter0#&lt;/p&gt;
&lt;h1 id=&quot;Lambda-Calculus&quot;&gt;&lt;a href=&quot;#Lambda-Calculus&quot; class=&quot;headerlink&quot; title=&quot;Lambda Calculus&quot;&gt;&lt;/a&gt;Lambda Calculus&lt;/
    
    </summary>
    
      <category term="Functional programming,Scala" scheme="http://www.sweatbuffer.com/categories/Functional-programming-Scala/"/>
    
    
      <category term="Functional programming" scheme="http://www.sweatbuffer.com/tags/Functional-programming/"/>
    
      <category term="Scala" scheme="http://www.sweatbuffer.com/tags/Scala/"/>
    
  </entry>
  
  <entry>
    <title>有关 Statistical Deobfuscation of Android Applications</title>
    <link href="http://www.sweatbuffer.com/2017/01/11/tags-%20%5B%E8%AE%BA%E6%96%87%E5%AD%A6%E4%B9%A0,%20obfuscation,%20Android%EF%BC%8Cdeobfuscation%5D/"/>
    <id>http://www.sweatbuffer.com/2017/01/11/tags- [论文学习, obfuscation, Android，deobfuscation]/</id>
    <published>2017-01-11T14:19:42.000Z</published>
    <updated>2017-01-11T14:19:42.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Abstract"><a href="#Abstract" class="headerlink" title="Abstract"></a>Abstract</h1><p>这篇论文提出了一个新的 恢复混淆 的方法，对象是 Android APK , 基于 概率性的’大代码’学习（probabilistic learning of large code） 的这么一种方式。</p>
<p>核心 Idea 是 通过上千种没有经过混淆的 Android软件，学习一种概率性的模型，然后利用这种模型去恢复新的，没见过的Android APK。</p>
<p>这篇文章的核心关注点是恢复 布局混淆(layout obfuscation)。<br>注：( 混淆技术分为几种：layout obfuscation（布局混淆）， Control obfuscation（控制流混淆）, Data Obfuscation（数据混淆）and Preventive Obfuscation（预防混淆）.)</p>
<h2 id="布局混淆"><a href="#布局混淆" class="headerlink" title="布局混淆"></a><strong>布局混淆</strong></h2><p>是一种曾经很流行如今也在使用但并不高深的一种混淆技术。它会重命名程序的元素，例如：classes，packages 和 methods ， 使得理解程序的代码变得困难。</p>
<p>具体的来讲 这篇论文里：</p>
<ol>
<li>在概率性的图像化模型中，词组化 Android APK的布局混淆问题 </li>
<li>用丰富的 特点集和捕获 Android setting的约束条件 举例说明这个模型，既能确保语义等价和又能维持预测的高精准性。</li>
<li>显示如何调节 有力的推理和学习算法两者的平衡去实现 总体的预测和可拓展的概率性预测。</li>
</ol>
<p>作者提出了他们的方法 用一款叫： DEGUARD 的工具， 使用它：</p>
<ol>
<li>反逆向 已经使用了非常流行的 叫做 ProGuard 的良性的，开源的布局混淆工具的软件混淆过的 APK 。</li>
<li>推测 导入的三方库的良性 APK。</li>
<li>重命名经过了混淆的Android malware元素的名字。</li>
</ol>
<p>实验结果证明 DEGUARD 实践效果非常高效：他可以恢复 79.1% 经过 ProGuard混淆过的元素名字，91.3% 经混淆的引入的第三方库。而且他在恶意软件中揭示了 处理敏感数据的 字符串解码器和类名。</p>
<hr>
 <a id="more"></a>
<h1 id="介绍（Introduction）"><a href="#介绍（Introduction）" class="headerlink" title="介绍（Introduction）"></a>介绍（Introduction）</h1><p>这篇论文提出了一种新的方法，基于概率模型恢复经过混淆的Android Application的这么一种方法。我们的方法是使用 在 公共仓库（public repositories）中存在的大量的Android程序（被称为 “Big Code”）去学习，得到强有力的能捕获没有经过 混淆 的 Android 程序的核心特征的概率模型。然后使用这个概率模型去议题一种（概率性的）恢复混淆的的提案，对于已经混淆了的 Android applications。<br>我们的方法使得多样的安全的软件变为可能。例如，我们的系统成功的恢复了经过 ProGuard  混淆过的Android APK。</p>
<h2 id="焦点：布局混淆（Focus：Layout-Deobufscation）"><a href="#焦点：布局混淆（Focus：Layout-Deobufscation）" class="headerlink" title="焦点：布局混淆（Focus：Layout Deobufscation）"></a>焦点：布局混淆（Focus：Layout Deobufscation）</h2><p>这篇论文的关注点在于恢复  Android APK 的 布局混淆 。 一般的混淆技术包括其他的混淆方法（例如改变数据的表现方法，改变控制流等），布局混淆仍然保持着几乎所有的混淆工具的核心部分。</p>
<p>在布局混淆中，程序元素的名字持有重要的语义信息，被其他的没有语义信息的标识符所替代。例如，变量名，方法名，类名。重命名这些程序元素使得分析人员读和理解程序的代码变得困难无比（-，- 比如上个学期读smali代码的时候 看到一堆a,b,c,aa,ab,ac时心情有多难过。。）同时对于很多的安全情境下（比如保护知识产权也就是防止被偷代码）也都非常有用。</p>
<h2 id="优点和挑战-Benefit-and-Challenges"><a href="#优点和挑战-Benefit-and-Challenges" class="headerlink" title="优点和挑战(Benefit and Challenges)"></a>优点和挑战(Benefit and Challenges)</h2><p>这其中，恢复 Android apk 的布局混淆有着以下几类好处：</p>
<ul>
<li>它使得 安全分析师检查被 ProGuard 混淆过的 Android App变得更加简单。 </li>
<li>它可以识别 Android Apk里嵌入的第三方库。</li>
<li>它对于代码中某一特定的标识符可以实现自动搜索。</li>
</ul>
<p>然而，恢复布局混淆是一个难题。<br>原因是：一旦原有的名字在程序中被移除 和 被用缩写过的标识符替代的情况下，简单的单独的孤立的检查这么一个程序来恢复原有的名字可能性很小。</p>
<h2 id="从“大代码”中的概率性学习（Probabilistic-Learning-from-“Big-Code”）"><a href="#从“大代码”中的概率性学习（Probabilistic-Learning-from-“Big-Code”）" class="headerlink" title="从“大代码”中的概率性学习（Probabilistic Learning from “Big Code”）"></a>从“大代码”中的概率性学习（Probabilistic Learning from “Big Code”）</h2><p>为了解决 单独的考虑一个程序去恢复布局混淆很难的这么一个挑战，过去的几年里出现了新兴的 静态工具：从”Big Code”中来学习的概率模型，然后利用这个模型去面向一些难以解决的任务提供可能的解决方案。这些难以解决的任务例如：程序语言间的机械翻译(machine translation between programming languages)，静态代码合成（statistical code synthesis），and 在源代码中猜测名字，类型（predicting names and types in source code）。<br>好玩儿的是，缘于他们独特的特性，一些概率性的系统在开发社区中快速变得流行。</p>
<h2 id="我们的工作：-通过-“大代码”-的-Android-反混淆（This-work-Android-Deobfuscation-via-“Big-Code”）"><a href="#我们的工作：-通过-“大代码”-的-Android-反混淆（This-work-Android-Deobfuscation-via-“Big-Code”）" class="headerlink" title="我们的工作： 通过 “大代码” 的 Android 反混淆（This work: Android Deobfuscation via “Big Code”）"></a>我们的工作： 通过 “大代码” 的 Android 反混淆（This work: Android Deobfuscation via “Big Code”）</h2><p>以这些优点为动机，我们针对 恢复 Android 布局混淆 提出了一种新的方法，通过“学习”数千种 易获得的，未经混淆的 Android App。</p>
<p>技术性的来讲，我们的方法的工作机制是：把 预测被层次混淆过的标识符的名字 的问题 使用概率性图像模型分成若干 有结构的预测 。事实上，我们利用 Conditional Random Fields（CRFs） ,一个强有力的广泛应用于多种领域的模型（包括 计算机影像处理，自然语言处理）。 据我们所知，这是第一个利用 从”大代码“学习的概率图象模型 去处理核心安全类的问题。 使用我们的方法，我们提出了一个工具叫做 DEGUARD , 它可以以高预测率的自动的恢复 通过 ProGuard 层次混淆过的 Android Apk。 </p>
<h2 id="主要的贡献（Main-Contributions）"><a href="#主要的贡献（Main-Contributions）" class="headerlink" title="主要的贡献（Main Contributions）"></a>主要的贡献（Main Contributions）</h2><ul>
<li>一种结构性的预测方法用来执行概率性的 Android APK的层次混淆恢复。</li>
<li>能够干净的捕获 Android App 核心部分的特征和约束集。结合起来说，这些特征约束集可以确保我们的概率性预测的高预测利率和维持 App的原有语义。</li>
<li>一个复杂的大规模概率性系统叫 DEGUARD。</li>
<li>被 ProGuard 混淆过的在 open-source 上 Android App 和 恶意 Android App 使用 DEGUARD 的评价和估值。 我们的结果显示 DEGUARD 可以恢复被 ProGuard混淆过的 79.1% 的程序元素，以及识别 91.3% 使用的三方库，揭示 相关字符串编码器和恶意软件的类。</li>
</ul>
<hr>
<h1 id="综述（Overview）"><a href="#综述（Overview）" class="headerlink" title="综述（Overview）"></a>综述（Overview）</h1><p>在这一章节中我们对于 我们的 Android静态反混淆方法提出了一种非正式的综述。第一，我们讨论 ProGuard，一直都很广泛被应用的 Android App 混淆工具。之后我们提出了 DEGUARD 系统的核心步骤。最后我们的目标是提供一种 关于这个方法直观上的理解。全部的正式的细节在写一个章节里讨论。</p>
<h2 id="ProGuard"><a href="#ProGuard" class="headerlink" title="ProGuard"></a>ProGuard</h2><p>ProGuard 混淆程序的元素包括：fields名，方法名，类名，包名，通过用语义难以理解的字符串替代原有的名字。它同样移除不使用的类，field，方法去最小化输出 APK 的大小。ProGuard 同样处理 app 和 程序导入的三方库。程序导入三方库所以会隐藏在发布的 APK 中。</p>
<p>ProGuard 不可以混淆所有的程序元素，因为这样会改变程序原有的语义。例如： Android API 的 方法名字和静态文件参考的类的名字，这种一旦修改就会引发引用错误等问题，会使得程序不正常运转。</p>
<p>用一些工具比如：apktool，Dex2Jar，JavaDecompiler 可以很轻易地获得 Android代码。所以当一些函数的名字变成 ： </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">a obj = <span class="keyword">new</span> a();</div><div class="line">obj.c(str);</div></pre></td></tr></table></figure>
<p>就很难分析出代码的意图了，有好多啦。。。所以要看smali代码，看多了也就能看进去了。<br>值得注意的是：<code>ProGuard</code> 为了保护原有的程序语义不变 保持了一些程序的名字没有改变，例如： <code>SQLiteOpenHelper</code> 和 他的方法 <code>getWritableDatabase</code> 和 <code>rawQuery</code>，这些都是核心 Android API的一部分。</p>
<h2 id="DeGuard"><a href="#DeGuard" class="headerlink" title="DeGuard"></a>DeGuard</h2><p>todo</p>
<h3 id="Dependency-Graph"><a href="#Dependency-Graph" class="headerlink" title="Dependency Graph"></a>Dependency Graph</h3><p>todo</p>
<h3 id="Syntactic-and-Semantic-Constraints"><a href="#Syntactic-and-Semantic-Constraints" class="headerlink" title="Syntactic and Semantic Constraints"></a>Syntactic and Semantic Constraints</h3><p>todo</p>
<h3 id="Probabilistic-Prediction"><a href="#Probabilistic-Prediction" class="headerlink" title="Probabilistic Prediction"></a>Probabilistic Prediction</h3><p>todo</p>
<h2 id="Security-Applications"><a href="#Security-Applications" class="headerlink" title="Security Applications"></a>Security Applications</h2><p>todo</p>
<h2 id="Challenges"><a href="#Challenges" class="headerlink" title="Challenges"></a>Challenges</h2><p>todo</p>
<h2 id="Scope-and-Limitations"><a href="#Scope-and-Limitations" class="headerlink" title="Scope and Limitations"></a>Scope and Limitations</h2><p>todo</p>
<hr>
<h1 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h1><p>todo</p>
<h2 id="Problem-Statement"><a href="#Problem-Statement" class="headerlink" title="Problem Statement"></a>Problem Statement</h2><p>todo</p>
<h2 id="Dependency-Graph-1"><a href="#Dependency-Graph-1" class="headerlink" title="Dependency Graph"></a>Dependency Graph</h2><p>todo</p>
<h2 id="Features-and-Weights"><a href="#Features-and-Weights" class="headerlink" title="Features and Weights"></a>Features and Weights</h2><p>todo</p>
<h2 id="Conditional-Random-Fields"><a href="#Conditional-Random-Fields" class="headerlink" title="Conditional Random Fields"></a>Conditional Random Fields</h2><p>todo</p>
<h2 id="Prediction-via-MAP-Inference"><a href="#Prediction-via-MAP-Inference" class="headerlink" title="Prediction via MAP Inference"></a>Prediction via MAP Inference</h2><p>todo</p>
<h2 id="MAP-Inference-Example"><a href="#MAP-Inference-Example" class="headerlink" title="MAP Inference Example"></a>MAP Inference Example</h2><p>todo</p>
<h2 id="Learning-from-“Big-Code”"><a href="#Learning-from-“Big-Code”" class="headerlink" title="Learning from “Big Code”"></a>Learning from “Big Code”</h2><p>todo</p>
<hr>
<h1 id="Feature-Functions"><a href="#Feature-Functions" class="headerlink" title="Feature Functions"></a>Feature Functions</h1><p>todo</p>
<h2 id="Program-Elements"><a href="#Program-Elements" class="headerlink" title="Program Elements"></a>Program Elements</h2><p>todo</p>
<h3 id="Known-and-Unknown-Program-Elements"><a href="#Known-and-Unknown-Program-Elements" class="headerlink" title="Known and Unknown Program Elements"></a>Known and Unknown Program Elements</h3><p>todo </p>
<h3 id="Grouping-Method-Nodes"><a href="#Grouping-Method-Nodes" class="headerlink" title="Grouping Method Nodes"></a>Grouping Method Nodes</h3><p>todo</p>
<h2 id="Relationships"><a href="#Relationships" class="headerlink" title="Relationships"></a>Relationships</h2><p>todo</p>
<h3 id="Method-Relationships"><a href="#Method-Relationships" class="headerlink" title="Method Relationships"></a>Method Relationships</h3><p>todo</p>
<h3 id="Structural-Relationships"><a href="#Structural-Relationships" class="headerlink" title="Structural Relationships"></a>Structural Relationships</h3><p>todo </p>
<h3 id="Comparison-to-Other-Prediction-Systems"><a href="#Comparison-to-Other-Prediction-Systems" class="headerlink" title="Comparison to Other Prediction Systems"></a>Comparison to Other Prediction Systems</h3><p>todo</p>
<h2 id="Pairwise-Feature-Functions"><a href="#Pairwise-Feature-Functions" class="headerlink" title="Pairwise Feature Functions"></a>Pairwise Feature Functions</h2><p>todo</p>
<hr>
<h1 id="Constraints"><a href="#Constraints" class="headerlink" title="Constraints"></a>Constraints</h1><p>todo</p>
<h2 id="Naming-Constrains-for-Methods"><a href="#Naming-Constrains-for-Methods" class="headerlink" title="Naming Constrains for Methods"></a>Naming Constrains for Methods</h2><p>todo </p>
<h3 id="Example"><a href="#Example" class="headerlink" title="Example"></a>Example</h3><p>todo</p>
<h3 id="Expressing-Method-Constraints"><a href="#Expressing-Method-Constraints" class="headerlink" title="Expressing Method Constraints"></a>Expressing Method Constraints</h3><p>todo</p>
<h3 id="Deriving-Inequality-Constrains-for-Methods"><a href="#Deriving-Inequality-Constrains-for-Methods" class="headerlink" title="Deriving Inequality Constrains for Methods"></a>Deriving Inequality Constrains for Methods</h3><p>todo</p>
<h3 id="Result-On-the-Example"><a href="#Result-On-the-Example" class="headerlink" title="Result On the Example"></a>Result On the Example</h3><p>todo</p>
<h2 id="Naming-Constrains-for-Fields-Classes-and-Packages"><a href="#Naming-Constrains-for-Fields-Classes-and-Packages" class="headerlink" title="Naming Constrains for Fields,Classes,and Packages"></a>Naming Constrains for Fields,Classes,and Packages</h2><p>todo</p>
<hr>
<h1 id="Implementation-and-Evaluation"><a href="#Implementation-and-Evaluation" class="headerlink" title="Implementation and Evaluation"></a>Implementation and Evaluation</h1><p>todo</p>
<h2 id="The-DEGUARD-System"><a href="#The-DEGUARD-System" class="headerlink" title="The DEGUARD System"></a>The DEGUARD System</h2><p>todo</p>
<h3 id="Feature-Functions-and-Weights"><a href="#Feature-Functions-and-Weights" class="headerlink" title="Feature Functions and Weights"></a>Feature Functions and Weights</h3><p>todo</p>
<h3 id="MAP-Inference"><a href="#MAP-Inference" class="headerlink" title="MAP Inference"></a>MAP Inference</h3><p>todo</p>
<h2 id="Experimental-Evaluation"><a href="#Experimental-Evaluation" class="headerlink" title="Experimental Evaluation"></a>Experimental Evaluation</h2><p>todo</p>
<h3 id="ProGuard-Experiments"><a href="#ProGuard-Experiments" class="headerlink" title="ProGuard Experiments"></a>ProGuard Experiments</h3><p>todo </p>
<h3 id="ProGuard-Obfuscated-APKs"><a href="#ProGuard-Obfuscated-APKs" class="headerlink" title="ProGuard-Obfuscated APKs"></a>ProGuard-Obfuscated APKs</h3><h3 id="Task1-Predicting-Program-Element-Names"><a href="#Task1-Predicting-Program-Element-Names" class="headerlink" title="Task1: Predicting Program Element Names."></a>Task1: Predicting Program Element Names.</h3><h3 id="Task2-Predicting-Third-party-Libraries"><a href="#Task2-Predicting-Third-party-Libraries" class="headerlink" title="Task2: Predicting Third-party Libraries."></a>Task2: Predicting Third-party Libraries.</h3><h3 id="Prediction-Speed"><a href="#Prediction-Speed" class="headerlink" title="Prediction Speed"></a>Prediction Speed</h3><h3 id="Summary-of-ProGuard-Experiments"><a href="#Summary-of-ProGuard-Experiments" class="headerlink" title="Summary of ProGuard Experiments"></a>Summary of ProGuard Experiments</h3><h2 id="Experiments-with-Malware-Samples"><a href="#Experiments-with-Malware-Samples" class="headerlink" title="Experiments with Malware Samples"></a>Experiments with Malware Samples</h2><h3 id="Revealing-Base64-String-Decoders"><a href="#Revealing-Base64-String-Decoders" class="headerlink" title="Revealing Base64 String Decoders"></a>Revealing Base64 String Decoders</h3><h3 id="Revealing-Sensitive-Data-Usage"><a href="#Revealing-Sensitive-Data-Usage" class="headerlink" title="Revealing Sensitive Data Usage"></a>Revealing Sensitive Data Usage</h3><h3 id="Limitations"><a href="#Limitations" class="headerlink" title="Limitations"></a>Limitations</h3><h1 id="Related-Work"><a href="#Related-Work" class="headerlink" title="Related Work"></a>Related Work</h1><h2 id="Probabilistic-models-for-programs"><a href="#Probabilistic-models-for-programs" class="headerlink" title="Probabilistic models for programs"></a>Probabilistic models for programs</h2><p>#Conclusion</p>
<hr>
]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;Abstract&quot;&gt;&lt;a href=&quot;#Abstract&quot; class=&quot;headerlink&quot; title=&quot;Abstract&quot;&gt;&lt;/a&gt;Abstract&lt;/h1&gt;&lt;p&gt;这篇论文提出了一个新的 恢复混淆 的方法，对象是 Android APK , 基于 概率性的’大代码’学习（probabilistic learning of large code） 的这么一种方式。&lt;/p&gt;
&lt;p&gt;核心 Idea 是 通过上千种没有经过混淆的 Android软件，学习一种概率性的模型，然后利用这种模型去恢复新的，没见过的Android APK。&lt;/p&gt;
&lt;p&gt;这篇文章的核心关注点是恢复 布局混淆(layout obfuscation)。&lt;br&gt;注：( 混淆技术分为几种：layout obfuscation（布局混淆）， Control obfuscation（控制流混淆）, Data Obfuscation（数据混淆）and Preventive Obfuscation（预防混淆）.)&lt;/p&gt;
&lt;h2 id=&quot;布局混淆&quot;&gt;&lt;a href=&quot;#布局混淆&quot; class=&quot;headerlink&quot; title=&quot;布局混淆&quot;&gt;&lt;/a&gt;&lt;strong&gt;布局混淆&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;是一种曾经很流行如今也在使用但并不高深的一种混淆技术。它会重命名程序的元素，例如：classes，packages 和 methods ， 使得理解程序的代码变得困难。&lt;/p&gt;
&lt;p&gt;具体的来讲 这篇论文里：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在概率性的图像化模型中，词组化 Android APK的布局混淆问题 &lt;/li&gt;
&lt;li&gt;用丰富的 特点集和捕获 Android setting的约束条件 举例说明这个模型，既能确保语义等价和又能维持预测的高精准性。&lt;/li&gt;
&lt;li&gt;显示如何调节 有力的推理和学习算法两者的平衡去实现 总体的预测和可拓展的概率性预测。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;作者提出了他们的方法 用一款叫： DEGUARD 的工具， 使用它：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;反逆向 已经使用了非常流行的 叫做 ProGuard 的良性的，开源的布局混淆工具的软件混淆过的 APK 。&lt;/li&gt;
&lt;li&gt;推测 导入的三方库的良性 APK。&lt;/li&gt;
&lt;li&gt;重命名经过了混淆的Android malware元素的名字。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;实验结果证明 DEGUARD 实践效果非常高效：他可以恢复 79.1% 经过 ProGuard混淆过的元素名字，91.3% 经混淆的引入的第三方库。而且他在恶意软件中揭示了 处理敏感数据的 字符串解码器和类名。&lt;/p&gt;
&lt;hr&gt;
    
    </summary>
    
      <category term="论文学习" scheme="http://www.sweatbuffer.com/categories/%E8%AE%BA%E6%96%87%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="论文学习" scheme="http://www.sweatbuffer.com/tags/%E8%AE%BA%E6%96%87%E5%AD%A6%E4%B9%A0/"/>
    
      <category term="obfuscation" scheme="http://www.sweatbuffer.com/tags/obfuscation/"/>
    
      <category term="Android，deobfuscation" scheme="http://www.sweatbuffer.com/tags/Android%EF%BC%8Cdeobfuscation/"/>
    
  </entry>
  
  <entry>
    <title>关于Android NDK开发（一） - NDK 和 JNI 简介</title>
    <link href="http://www.sweatbuffer.com/2017/01/11/ndk%E7%AE%80%E4%BB%8B/"/>
    <id>http://www.sweatbuffer.com/2017/01/11/ndk简介/</id>
    <published>2017-01-11T00:57:55.000Z</published>
    <updated>2017-01-11T00:57:55.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="0x00-NDK-简介"><a href="#0x00-NDK-简介" class="headerlink" title="0x00 NDK 简介"></a>0x00 NDK 简介</h1><hr>
<h2 id="什么是Android-NDK"><a href="#什么是Android-NDK" class="headerlink" title="什么是Android NDK"></a>什么是Android NDK</h2><p><a href="https://developer.android.com/ndk/guides/index.html" target="_blank" rel="external">NDK</a>是(Native Development Kit)的缩写，也就是开发Native的套件或者说工具集合。<br>NDK提供了一系列的工具，帮助开发者快速开发C/C++的动态库(.SO文件)，并且能够自动将 so和java 应用一起打包成apk. </p>
<hr>
<h2 id="NDK存在的意义"><a href="#NDK存在的意义" class="headerlink" title="NDK存在的意义"></a>NDK存在的意义</h2><p>Android 的 SDK 是基于JAVA实现，意味着基于 SDK 进行开发的应用都必须使用JAVA语言。然而 C/C++ 与 JAVA 各有各的优点何用途，为了能支持 C/C++ 谷歌在开发初期就使其 Dalvik虚拟机支持 JNI 编程方式，也就是第三方应用的 JAVA代码完全可以通过本机的(JNI)框架来调用Native动态库里的函数(.so文件里的各种函数).</p>
<p>也就是说 因为有 NDK 和 JNI 的支持， Android平台可以实现 “JAVA + C”的这么一种编程方式。</p>
<hr>
<h2 id="为什么要用-NDK-（什么时候需要用-C）"><a href="#为什么要用-NDK-（什么时候需要用-C）" class="headerlink" title="为什么要用 NDK （什么时候需要用 C）"></a>为什么要用 NDK （什么时候需要用 C）</h2><ul>
<li>可以方便的使用现有的开源库。（大部分的开源库都是用 C/C++ 编写的）</li>
<li>提高程序的执行效率。（很多要求高性能的应用使用C开发，从而提高应用程序的执行效率）。</li>
<li>代码的保护。（apk 的 JAVA 层代码很容易被反编译，而 C/C++ 库的反汇编难度比较大）。</li>
<li>底层程序设计。（例如，应用程序不依赖 Dalvik JAVA 虚拟机 ）</li>
</ul>
<hr>
<h1 id="0x01-JNI-简介"><a href="#0x01-JNI-简介" class="headerlink" title="0x01 JNI 简介"></a>0x01 JNI 简介</h1><hr>
<a id="more"></a>
<h2 id="什么是-JNI"><a href="#什么是-JNI" class="headerlink" title="什么是 JNI"></a>什么是 JNI</h2><p>JNI 是一种在JAVA虚拟机控制下执行代码的标准机制。代码被编写成汇编程序或者 C/C++ 程序，并组装为动态组。也就允许了非静态绑定用法。提供了在 JAVA 平台上调用C/C++的一种途径，反之亦然。</p>
<hr>
<h2 id="JNI-的优势"><a href="#JNI-的优势" class="headerlink" title="JNI 的优势"></a>JNI 的优势</h2><p>与其它类似接口（NETSCAP JAVA 运行接口，Microsoft 的原始本地接口，COM/JAVA 接口）相比，JNI主要的竞争优势在于： </p>
<p>它在设计之初就确保了二进制的兼容性，JNI 编写的应用程序兼容性以及在某些平台上的 JAVA 虚拟机兼容性（不只 Dalvik 虚拟机 还有一般的 JAVA 虚拟机）。<br>这就是为什么 C/C++ 编译后的代码无论在任何平台上都能执行。不过一些早期版本并不支持二进制兼容。<br><img src="http://static.zybuluo.com/sweatbuffer/vpwlaexo9pe4yzv26s47dfw9/JNI.PNG" alt="JNI.PNG-100.8kB"></p>
<hr>
<h2 id="JNI-组织结构"><a href="#JNI-组织结构" class="headerlink" title="JNI 组织结构"></a>JNI 组织结构</h2><p><img src="http://static.zybuluo.com/sweatbuffer/ey0wvzv5zfr7u9bsmx1u1lan/JNI-interface.jpg" alt="JNI-interface.jpg-50kB"><br>这张 JNI 函数表的组成就像 C++ 的虚函数表。虚拟机可以运行多张函数表，举例来说，一张调试函数表，另一张是调用函数表。JNI 接口指针仅在当前线程中起作用。</p>
<p>这意味着 指针不能从一个线程进入另一个线程。 然而， 可以在不同的线程中调用本地方法。</p>
<p>示例代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="function">jdouble <span class="title">Java_pkg_Cls_f__ILjava_lang_String_2</span> <span class="params">(JNIEnv *env, jobject obj, jint i, jstring s)</span></span></div><div class="line">&#123;</div><div class="line">     <span class="keyword">const</span> <span class="keyword">char</span> *str = (*env)-&gt;GetStringUTFChars(env, s, <span class="number">0</span>); </div><div class="line">     (*env)-&gt;ReleaseStringUTFChars(env, s, str); </div><div class="line">     <span class="keyword">return</span> <span class="number">10</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<ul>
<li>*env   - 一个接口指针</li>
<li>obj   - 在本地方法中声明的对象引用</li>
<li>i 和 s - 用于传递的参数</li>
</ul>
<p>原始类型（Primitive Type）在虚拟机和本机代码进行拷贝，对象之间使用引用进行传递。VM（虚拟机)要追踪所有传递给本地代码的对象引用。GC无法释放所有传递给本地代码的对象引用。与此同时，本机代码应该通知VM不需要的对象引用。</p>
<hr>
<h2 id="局部引用和全局引用"><a href="#局部引用和全局引用" class="headerlink" title="局部引用和全局引用"></a>局部引用和全局引用</h2><p>JNI 定义了三种引用类型：<strong><code>局部引用</code></strong>，<strong><code>全局引用</code></strong>和<strong><code>全局弱引用</code></strong>。</p>
<h3 id="局部引用"><a href="#局部引用" class="headerlink" title="局部引用"></a>局部引用</h3><p><code>局部引用</code>在方法完成之前是有效的。所有通过 JNI 函数返回的 JAVA 对象都是本地引用。程序员希望 VM 会清空所有的局部引用，然而局部引用尽在其创建的线程里可用。如果有必要，局部引用可以通过接口中的 <strong><code>DeletteLocalRef JNI</code></strong> 方法立即释放：<br><figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">jclass clazz;</div><div class="line">clazz = (*env)-&gt;FindClass(env, <span class="string">"java/lang/String"</span>);</div><div class="line">...</div><div class="line">(*env)-&gt;DeleteLocalRef(env, clazz)</div></pre></td></tr></table></figure></p>
<h3 id="全局引用"><a href="#全局引用" class="headerlink" title="全局引用"></a>全局引用</h3><p><code>全局引用</code>在完全释放之前都是有效的。要创建一个全局引用，需要调用 <strong><code>NewGlobalRef</code></strong> 方法。如果全局引用不是必须的，可以通过 <strong><code>DeleteGlobalRef</code></strong> 方法删除：<br><figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">jclass localClazz;</div><div class="line">jclass globalClazz;</div><div class="line">...</div><div class="line">localClazz = (*env)-&gt;FindClass(env, <span class="string">"java/lang/String"</span>);</div><div class="line">globalClazz = (*env)-&gt;NewGlobalRef(env, localClazz);</div><div class="line">...</div><div class="line">(*env)-&gt;DeleteLocalRef(env, localClazz);</div></pre></td></tr></table></figure></p>
<hr>
<h2 id="错误"><a href="#错误" class="headerlink" title="错误"></a>错误</h2><p>JNI 不会检查 <strong><code>NullPointerException</code></strong>、<strong><code>IllegalArgumentException</code></strong>这样的错误，原因是：</p>
<ul>
<li>性能下降</li>
<li>在绝大多数 C 的库函数中，很难避免错误发生。</li>
</ul>
<p>JNI 允许用户使用 JAVA 异常处理。 大部分 JNI 方法会返回错误代码 但是本身并不会报出异常。因此，很有必要再代码本身进行处理，将异常抛给 JAVA。</p>
<p>在 JNI 内部，首先会检查调用函数返回的错误代码，之后会调用 <strong><code>ExpertOccurred()</code></strong> 返回一个错误对象。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="function">jthrowable <span class="title">ExceptionOccurred</span><span class="params">(JNIEnv *env)</span></span>;</div></pre></td></tr></table></figure></p>
<hr>
<h2 id="JNI-原始类型"><a href="#JNI-原始类型" class="headerlink" title="JNI 原始类型"></a>JNI 原始类型</h2><p>JNI 有自己的原始数据类型和数据引用类型。</p>
<table>
<thead>
<tr>
<th style="text-align:center">JAVA类型</th>
<th style="text-align:center">本地类型（JNI）</th>
<th style="text-align:center">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">boolean（布尔型）</td>
<td style="text-align:center">jboolean</td>
<td style="text-align:center">无符号 8 bit</td>
</tr>
<tr>
<td style="text-align:center">byte(字节型)</td>
<td style="text-align:center">jbyte</td>
<td style="text-align:center">有符号 8 bit</td>
</tr>
<tr>
<td style="text-align:center">char（字符型）</td>
<td style="text-align:center">jchar</td>
<td style="text-align:center">无符号 16 bit</td>
</tr>
<tr>
<td style="text-align:center">short（短整型）</td>
<td style="text-align:center">jshort</td>
<td style="text-align:center">有符号 16 bit</td>
</tr>
<tr>
<td style="text-align:center">int（整形）</td>
<td style="text-align:center">jint</td>
<td style="text-align:center">有符号 32 bit</td>
</tr>
<tr>
<td style="text-align:center">long（长整形）</td>
<td style="text-align:center">jlong</td>
<td style="text-align:center">有符号 64 bit</td>
</tr>
<tr>
<td style="text-align:center">float（浮点型）</td>
<td style="text-align:center">jfloat</td>
<td style="text-align:center">32 bit</td>
</tr>
<tr>
<td style="text-align:center">double（双精度浮点型）</td>
<td style="text-align:center">jdouble</td>
<td style="text-align:center">64 bit</td>
</tr>
<tr>
<td style="text-align:center">void（空型）</td>
<td style="text-align:center">void</td>
<td style="text-align:center">N/A</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="JNI-引用类型"><a href="#JNI-引用类型" class="headerlink" title="JNI 引用类型"></a>JNI 引用类型</h2><p><img src="http://static.zybuluo.com/sweatbuffer/8gl6mko7omuy5gs7xwpoowi9/jni%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B.png" alt="jni引用类型.png-38.8kB"></p>
<hr>
<h2 id="改进的-UTF-8-编码"><a href="#改进的-UTF-8-编码" class="headerlink" title="改进的 UTF-8 编码"></a>改进的 UTF-8 编码</h2><p>JNI 使用改进的 UTF-8 来表现不同的字符串类型。JAVA 使用 UTF-16 编码。 UTF-8 编码主要适用于 C 语言， 因为他们的编码把 u000 表示为 0xc0，而不是通常的 0x00。 使用改进的字符串可以使得 只包含非空 ASCII 的字符串编码只可以用一个字节（byte）表示。</p>
<hr>
<h2 id="JNI-函数"><a href="#JNI-函数" class="headerlink" title="JNI 函数"></a>JNI 函数</h2><p>JNI 接口不仅有自己的数据集（dataset）也有自己的函数。回顾这些数据集和函数需要花费我们很多时间。可以从官方文档中找到更多信息：</p>
<p><a href="http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html" target="_blank" rel="external">JNI 官方文档入口</a></p>
<hr>
<h2 id="JNI-函数使用示例"><a href="#JNI-函数使用示例" class="headerlink" title="JNI 函数使用示例"></a>JNI 函数使用示例</h2><p>下面通过简短的例子确保你对这些资料所讲的内容有了正确的理解：<br><figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;jni.h&gt;</span></span></div><div class="line">    ...</div><div class="line">JavaVM *jvm;</div><div class="line">JNIEnv *env;</div><div class="line">JavaVMInitArgs vm_args;</div><div class="line">JavaVMOption* options = <span class="keyword">new</span> JavaVMOption[<span class="number">1</span>];</div><div class="line">options[<span class="number">0</span>].optionString = <span class="string">"-Djava.class.path=/usr/lib/java"</span>;</div><div class="line">vm_args.version = JNI_VERSION_1_6;</div><div class="line">vm_args.nOptions = <span class="number">1</span>;</div><div class="line">vm_args.options = options;</div><div class="line">vm_args.ignoreUnrecognized = <span class="literal">false</span>;</div><div class="line">JNI_CreateJavaVM(&amp;jvm, &amp;env, &amp;vm_args);</div><div class="line"><span class="keyword">delete</span> options;</div><div class="line">jclass cls = env-&gt;FindClass(<span class="string">"Main"</span>);</div><div class="line">jmethodID mid = env-&gt;GetStaticMethodID(cls, <span class="string">"test"</span>, <span class="string">"(I)V"</span>);</div><div class="line">env-&gt;CallStaticVoidMethod(cls, mid, <span class="number">100</span>);</div><div class="line">jvm-&gt;DestroyJavaVM();</div></pre></td></tr></table></figure></p>
<p>大体来看这是一个 C 的代码 然后他应该是从 C 这边调用 JAVA ，我们逐个分析：</p>
<ul>
<li><code>JavaVM</code>           - 提供了一个接口，可以调用函数创建，删除 JAVA 虚拟机.</li>
<li><code>JNIEnv</code>           - 确保了大多数的 JNI 函数。</li>
<li><code>JavaVMInitArgs</code>   - Java 虚拟机参数</li>
<li><code>JavaVMOption</code>     - Java 虚拟机选项</li>
</ul>
<p>JNI 的 <code>_CreateJavaVM()</code> 方法初始化 JAVA 虚拟机并向 JNI 接口返回一个指针, <code>JNI_DestroyJavaVM()</code> 方法可以载入创建更好的 JAVA 虚拟机。</p>
<hr>
<h2 id="线程"><a href="#线程" class="headerlink" title="线程"></a>线程</h2><p>内核负责管理所有在 Lniux 上运行的线程。线程通过 <code>AttachCurrentThread</code> 和 <code>AttachCurrentThreadAsDaemon</code> 函数附加到 JAVA 虚拟机。 如果线程没有被添加成功，则不能访问 JNIEnv。Android 系统不能停止 JNI 创建的线程， 即使 GC（Garbage Collection）在运行释放内存时也不行。直到调用 <code>DetachCurrentThread</code> 方法，该线程才会从 JAVA 虚拟机脱离。</p>
<hr>
<p>作者 <a href="http://weibo.com/7Seven7King7" target="_blank" rel="external">@sweatbuffer</a><br>2017 年 01月 07日    </p>
]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;0x00-NDK-简介&quot;&gt;&lt;a href=&quot;#0x00-NDK-简介&quot; class=&quot;headerlink&quot; title=&quot;0x00 NDK 简介&quot;&gt;&lt;/a&gt;0x00 NDK 简介&lt;/h1&gt;&lt;hr&gt;
&lt;h2 id=&quot;什么是Android-NDK&quot;&gt;&lt;a href=&quot;#什么是Android-NDK&quot; class=&quot;headerlink&quot; title=&quot;什么是Android NDK&quot;&gt;&lt;/a&gt;什么是Android NDK&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://developer.android.com/ndk/guides/index.html&quot;&gt;NDK&lt;/a&gt;是(Native Development Kit)的缩写，也就是开发Native的套件或者说工具集合。&lt;br&gt;NDK提供了一系列的工具，帮助开发者快速开发C/C++的动态库(.SO文件)，并且能够自动将 so和java 应用一起打包成apk. &lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;NDK存在的意义&quot;&gt;&lt;a href=&quot;#NDK存在的意义&quot; class=&quot;headerlink&quot; title=&quot;NDK存在的意义&quot;&gt;&lt;/a&gt;NDK存在的意义&lt;/h2&gt;&lt;p&gt;Android 的 SDK 是基于JAVA实现，意味着基于 SDK 进行开发的应用都必须使用JAVA语言。然而 C/C++ 与 JAVA 各有各的优点何用途，为了能支持 C/C++ 谷歌在开发初期就使其 Dalvik虚拟机支持 JNI 编程方式，也就是第三方应用的 JAVA代码完全可以通过本机的(JNI)框架来调用Native动态库里的函数(.so文件里的各种函数).&lt;/p&gt;
&lt;p&gt;也就是说 因为有 NDK 和 JNI 的支持， Android平台可以实现 “JAVA + C”的这么一种编程方式。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;为什么要用-NDK-（什么时候需要用-C）&quot;&gt;&lt;a href=&quot;#为什么要用-NDK-（什么时候需要用-C）&quot; class=&quot;headerlink&quot; title=&quot;为什么要用 NDK （什么时候需要用 C）&quot;&gt;&lt;/a&gt;为什么要用 NDK （什么时候需要用 C）&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;可以方便的使用现有的开源库。（大部分的开源库都是用 C/C++ 编写的）&lt;/li&gt;
&lt;li&gt;提高程序的执行效率。（很多要求高性能的应用使用C开发，从而提高应用程序的执行效率）。&lt;/li&gt;
&lt;li&gt;代码的保护。（apk 的 JAVA 层代码很容易被反编译，而 C/C++ 库的反汇编难度比较大）。&lt;/li&gt;
&lt;li&gt;底层程序设计。（例如，应用程序不依赖 Dalvik JAVA 虚拟机 ）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id=&quot;0x01-JNI-简介&quot;&gt;&lt;a href=&quot;#0x01-JNI-简介&quot; class=&quot;headerlink&quot; title=&quot;0x01 JNI 简介&quot;&gt;&lt;/a&gt;0x01 JNI 简介&lt;/h1&gt;&lt;hr&gt;
    
    </summary>
    
      <category term="Android安全" scheme="http://www.sweatbuffer.com/categories/Android%E5%AE%89%E5%85%A8/"/>
    
    
      <category term="Android" scheme="http://www.sweatbuffer.com/tags/Android/"/>
    
      <category term="NDK" scheme="http://www.sweatbuffer.com/tags/NDK/"/>
    
      <category term="JNI" scheme="http://www.sweatbuffer.com/tags/JNI/"/>
    
      <category term="Security" scheme="http://www.sweatbuffer.com/tags/Security/"/>
    
  </entry>
  
  <entry>
    <title>生病了，2017第一场病</title>
    <link href="http://www.sweatbuffer.com/2017/01/10/%E7%94%9F%E7%97%85/"/>
    <id>http://www.sweatbuffer.com/2017/01/10/生病/</id>
    <published>2017-01-10T04:20:16.000Z</published>
    <updated>2017-01-10T04:20:16.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="难受。。。昨天从下午四点开始就感觉不消化，难受。忍到了6点跟博士请假回家休养。。然后1点开始-像开了阀门的水龙头一样的在往外脱水。。。。。。。。好像好久都没这样拉肚子过了。。。。也可能是以前积攒的很多，一下再爆发力。。。"><a href="#难受。。。昨天从下午四点开始就感觉不消化，难受。忍到了6点跟博士请假回家休养。。然后1点开始-像开了阀门的水龙头一样的在往外脱水。。。。。。。。好像好久都没这样拉肚子过了。。。。也可能是以前积攒的很多，一下再爆发力。。。" class="headerlink" title="难受。。。昨天从下午四点开始就感觉不消化，难受。忍到了6点跟博士请假回家休养。。然后1点开始 像开了阀门的水龙头一样的在往外脱水。。。。。。。。好像好久都没这样拉肚子过了。。。。也可能是以前积攒的很多，一下再爆发力。。。"></a>难受。。。昨天从下午四点开始就感觉不消化，难受。忍到了6点跟博士请假回家休养。。然后1点开始 像开了阀门的水龙头一样的在往外脱水。。。。。。。。好像好久都没这样拉肚子过了。。。。也可能是以前积攒的很多，一下再爆发力。。。</h2><hr>
<h2 id="病从口入嘛-新的一年我要打理好自己的身体。。。健健康康的。。。生病的时候心里比较脆弱。。。比较难受"><a href="#病从口入嘛-新的一年我要打理好自己的身体。。。健健康康的。。。生病的时候心里比较脆弱。。。比较难受" class="headerlink" title="病从口入嘛 新的一年我要打理好自己的身体。。。健健康康的。。。生病的时候心里比较脆弱。。。比较难受"></a>病从口入嘛 新的一年我要打理好自己的身体。。。健健康康的。。。生病的时候心里比较脆弱。。。比较难受</h2>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;难受。。。昨天从下午四点开始就感觉不消化，难受。忍到了6点跟博士请假回家休养。。然后1点开始-像开了阀门的水龙头一样的在往外脱水。。。。。。。。好像好久都没这样拉肚子过了。。。。也可能是以前积攒的很多，一下再爆发力。。。&quot;&gt;&lt;a href=&quot;#难受。。。昨天从下午
    
    </summary>
    
      <category term="个人日志" scheme="http://www.sweatbuffer.com/categories/%E4%B8%AA%E4%BA%BA%E6%97%A5%E5%BF%97/"/>
    
    
      <category term="生病" scheme="http://www.sweatbuffer.com/tags/%E7%94%9F%E7%97%85/"/>
    
  </entry>
  
  <entry>
    <title>Hello World</title>
    <link href="http://www.sweatbuffer.com/2017/01/07/Hello%20World/"/>
    <id>http://www.sweatbuffer.com/2017/01/07/Hello World/</id>
    <published>2017-01-07T04:36:07.000Z</published>
    <updated>2017-01-07T04:36:07.000Z</updated>
    
    <content type="html"><![CDATA[<p>说一下为什么开始写个人博客，是因为最近在逛博客的时候发现大家都好像再用hexo，所以感觉好神奇想尝一下味道。</p>
<p>第二个原因就是整理笔记的时候我就一直在想整理到网上也不错，可是一直都没动手，正好看到了hexo 所以想着试试看看。</p>
<p>感觉好神奇 静态的。渍渍渍。。。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;说一下为什么开始写个人博客，是因为最近在逛博客的时候发现大家都好像再用hexo，所以感觉好神奇想尝一下味道。&lt;/p&gt;
&lt;p&gt;第二个原因就是整理笔记的时候我就一直在想整理到网上也不错，可是一直都没动手，正好看到了hexo 所以想着试试看看。&lt;/p&gt;
&lt;p&gt;感觉好神奇 静态的。
    
    </summary>
    
    
  </entry>
  
</feed>
