fp-match

jsdt發表於2019-02-16

引言

js的模式匹配不強大,但是也有一些應用,最近在利用業餘週末時間斷續系統性的學scala,我學習scala目的就是理解和掌握它的函數語言程式設計,整體還沒學完。在這篇文章中會js結合scala的方式一起對比分析總結下,不說明預設是js寫法。

Destructure

Object

let name;
let {people:{age=Infinity,name}} = {people:{name:"JSDT"}}
// name "JSDT"

Array

let [a=1,b=2,c]=[`a`,]
// a `a` 、 b 2 、c `undefined`

Function

function JSDT([first,...rest]) {
    console.log(first,rest)
}
JSDT([1,2,3,4]);
//1,[2,3,4]

ADT(Algebraic Data Type)

上述本質來說基於位置match,基礎且常用,scala中也有,比較基礎,我不想重複列舉了。在js中不支援自定義型別匹配,但是在模式匹配中這是重要一環,由於最近在學scala,所以借鑑一下里面的思想和實現方式,因為其原生提供ADT方式的match。

原生型別(Scala)

  def acceptAny(x:Any):String={
    x  match {
      case s:String =>"a string"
      case i:Int if(i<20) => s"an int less than 20: $i"
      case  _ => "don`t know"
    }
  }
   def main(args: Array[String]): Unit = {
      println(acceptAny(10));  //an int less than 20: 10
   }

自定義資料型別(scala)

case object Nil extends List[Nothing]

case class Cons[+A](head: A, tail: List[A]) extends List[A]
<!------------------------------->
def sum(ints: List[Int]): Int = ints match {
  case Nil => 0 // 空list 返回0
  case Cons(x,xs) => x + sum(xs) // recursive 求和
}

  val x = List(1,2,3,4,5) match {
    case Cons(x, Cons(2, Cons(4, _))) => x
    case Nil => 42
    case Cons(x, Cons(y, Cons(3, Cons(4, _)))) => x + y  
    case Cons(h, t) => h + sum(t)
    case _ => 101
  }

  def main(args: Array[String]): Unit = {
   println( sum(List(1,2,3)))  //6
   println( x)  //3

  }

說明 為了搞明白和執行這個例子研究了有好一會兒,書上(scala函數語言程式設計Page:25)寫的沒問題,但是寫的不完整,我做了部分補充。
sum示例中模式匹配空構造型別Nil和非空構造型別Cons(由head和tail{tail由List構成}構成), 求和是通過遞迴的方式;
x match雖然case3、4、5都匹配,但是第一次匹配上的才會生效。
總的來說ADT這種方式優點是靈活,藉助這種強大的自定義型別匹配系統,可以簡化程式碼結構,使程式碼更易讀和維護。

自定義資料型別

const ListOf = T => {
    var List = Type({
        Nil:[],
        Cons:[T,List]
    });
    return List;
}
const LoN = ListOf(Number);
let list= LoN.Cons(1,LoN.Cons(2,LoN.Cons(3,LoN.Nil)));
// let list= LoN.Cons(1);

const sum = LoN.case({
    Cons:(head,tail) => head + sum(tail),
    Nil:(x) => 0
});
console.log(sum(list));  //6

說明 js本身不支援adt的方式匹配,藉助第三方工具union-type可以實現,上述我寫了一個和scala sum模式匹配功能相同的match例子,由於是非原生,所以寫法上冗餘,但其思想上和scala一樣,只是形式上不一樣。