国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Elm入門實(shí)踐(二)——類型篇

ZHAO_ / 1267人閱讀

摘要:如果不聲明類型呢如果注釋掉類型注解重新編譯,還是會(huì)報(bào)錯(cuò),只是錯(cuò)誤信息變了,這次是第行即使沒有顯式的類型注解,的類型推導(dǎo)系統(tǒng)也會(huì)發(fā)揮作用,此處通過類型推導(dǎo)認(rèn)為函數(shù)的參數(shù)應(yīng)該是字符串,但是傳入了數(shù)字,因此報(bào)錯(cuò)。

記得Facebook曾經(jīng)在一次社區(qū)活動(dòng)上說過,隨著他們?cè)絹碓蕉嗟厥褂肑avascript,很快就面臨了曾經(jīng)在PHP上遇到的問題:這東西到底是啥?

動(dòng)態(tài)語言就像把雙刃劍,你可以愛死它的靈活性,也可能因?yàn)橐粋€(gè)小的疏忽而損失慘重。Elm選擇了靜態(tài)強(qiáng)類型,這通常也是多數(shù)函數(shù)式語言的選擇,沒有了OO語言中的概念,強(qiáng)大的類型系統(tǒng)負(fù)責(zé)解決一切“這是什么?”的問題

類型注解

也可以叫做類型簽名,Elm 使用冒號(hào):來注明類型,在Hello world的基礎(chǔ)上,讓我們分別定義一個(gè)變量和函數(shù),并且注明類型

import Html exposing (..)
import Html.Attributes exposing (..)

elm : String
elm = "elm"

sayHello : String -> String
sayHello name = 
  "Hello, " ++ name

main =
  div [class "hello"] 
    [ span [] [text (sayHello elm)]
    ]

嘗試將elm的值"elm"改為數(shù)字,看看會(huì)發(fā)生什么?

Detected errors in 1 module.


-- TYPE MISMATCH ---------------------------------------------------------------

The type annotation for `elm` does not match its definition.

5| elm : String
         ^^^^^^
The type annotation is saying:

    String

But I am inferring that the definition has this type:

    number

編譯器發(fā)現(xiàn)了錯(cuò)誤,并且能夠定位到具體的行數(shù)。

如果不聲明類型呢?如果注釋掉類型注解

import Html exposing (..)
import Html.Attributes exposing (..)

--elm : String
elm = 6

--sayHello : String -> String
sayHello name = 
  "Hello, " ++ name

main =
  div [class "hello"] 
    [ span [] [text (sayHello elm)]
    ]

重新編譯,還是會(huì)報(bào)錯(cuò),只是錯(cuò)誤信息變了,這次是第14行:

Detected errors in 1 module.


-- TYPE MISMATCH ---------------------------------------------------------------

The argument to function `sayHello` is causing a mismatch.

14|                      sayHello elm)
                                  ^^^
Function `sayHello` is expecting the argument to be:

    String

But it is:

    number

即使沒有顯式的類型注解,Elm的類型推導(dǎo)系統(tǒng)也會(huì)發(fā)揮作用,此處通過類型推導(dǎo)認(rèn)為sayHello函數(shù)的參數(shù)應(yīng)該是字符串,但是傳入了數(shù)字,因此報(bào)錯(cuò)。

對(duì)比兩次不同的錯(cuò)誤提示可以看出,類型注解能讓編譯器更準(zhǔn)確地發(fā)現(xiàn)和定位錯(cuò)誤。隨著學(xué)習(xí)的深入你會(huì)慢慢喜歡上類型系統(tǒng)帶來的安全感:如果編譯失敗,明確的提示能幫助你快速定位問題。而只要編譯通過,程序就一定能運(yùn)行。

基本類型和List 基本類型

基本類型和多數(shù)語言是類似的,無非就是String, Char, Bool Int, Float,可以參考官網(wǎng)的literals。需要注意在Elm中,String必須用雙引號(hào),單引號(hào)是用來表示Char的,字符串單引號(hào)黨需要適應(yīng)一下。

List

嚴(yán)格來說List并不是類型,它的類型是List a,其中的a被稱作類型變量,這是因?yàn)長ist作為容器,它可以裝String,Int,或者什么都不裝,因此類型必須是動(dòng)態(tài)的:

> [ "Alice", "Bob" ]
[ "Alice", "Bob" ] : List String

> [ 1.0, 8.6, 42.1 ]
[ 1.0, 8.6, 42.1 ] : List Float

> []
[] : List a

關(guān)于類型變量后面會(huì)繼續(xù)討論,在這里我們只需要記住一點(diǎn):List不是類型,類似List String這樣的才是

由于參數(shù)只有一個(gè),Elm的List只能容納單一類型的元素,和Javascript來者不拒的List不同,下面這樣的是會(huì)被編譯器發(fā)現(xiàn)并報(bào)錯(cuò)的:

list = [1, "a"]
類型別名

類型別名用于組合或復(fù)用已知的類型,比如

type alias Name = String
type alias Age = Int
  
type alias User = {name: Name, age: Age}

user : User
user =
  { name = "Zhang zhe", age = 89 }
  
setUserName : String -> User -> User
setUserName name user = {user | name = name}

它不僅可以讓基本類型具備業(yè)務(wù)語義,還可以為復(fù)雜的數(shù)據(jù)結(jié)構(gòu)組合出合適的、語義化的類型。沒有別名的話,setUserName的類型簽名就得寫成下面這樣……一坨:

setUserName : String -> {name: String, age: Int} -> {name: String, age: Int}
Union Types

Union type 是Elm類型系統(tǒng)中最重要的部分之一,它用來表示一組可能的值,每個(gè)值叫做一個(gè)Tag,如下:

type Bool = True | False

type User = Anonymos | Authed

其中TrueFalseAnonymosAuthed 都是Tag名(注意Tag不是Type)。看起來很像枚舉?不只這樣,Union type強(qiáng)大的地方在于:Tag可以攜帶一組已知類型。上面的代碼我們雖然能區(qū)分兩類用戶,但并不能獲取認(rèn)證用戶的名稱,這時(shí)候就可以用已知類型結(jié)合Tag表達(dá):

type User = Anonymos | Authed String

當(dāng)我們創(chuàng)建Union type的時(shí)候,實(shí)際上為每個(gè)Tag都創(chuàng)建了相應(yīng)的值構(gòu)造器

> type User = Anonymous | Authed String

> Anonymous
Anonymous : User

> Authed
Authed : String -> User

不帶其它信息的Anonymous可以直接作為使用(想想TrueFalse),而帶有已知類型的Authed實(shí)際上是一個(gè)函數(shù),它接受String,返回User類型:

users : List User
users = [
  Anonymous, 
  Authed "Kpax"]

在Haskell中沒有Tag的叫法,相似的東西就叫值構(gòu)造器(value constructor),直接的表明了它的用途:構(gòu)建屬于該類型的值

Tag還可以被解構(gòu):

getAuthedUserName : User -> String
getAuthedUserName user =
  case user of 
    Anonymous ->
      ""
    Authed name ->
      name

這個(gè)函數(shù)返回Authed用戶的名稱,如果是Anonymous用戶則返回空字符串。

完整的可在在線編輯器中執(zhí)行的代碼如下:

import Html exposing (..)
import List

type User = Anonymous | Authed String

users : List User
users = [
  Anonymous, 
  Authed "Kpax",
  Authed "qin"]

getAuthedUserName : User -> String
getAuthedUserName user =
  case user of 
    Anonymous ->
      ""
    Authed name ->
      name      

main =
  div [] (List.map (text << getAuthedUserName) users)

text << getAuthedUserName 使用了Elm中的<<操作符實(shí)現(xiàn)兩個(gè)函數(shù)的compose,類似于lodash中的_.flowRight函數(shù)

Type variables

上面已經(jīng)提到了List a類型,其中a即類型變量,表示一個(gè)當(dāng)前還不確定的類型,類似于面向?qū)ο缶幊讨蟹盒偷母拍?/p>

map函數(shù)的類型簽名也使用了類型變量:

map : (a -> b) -> a -> b

這使得我們調(diào)用map函數(shù)map userToString user時(shí),只要保證user是User類型即可,map函數(shù)并不關(guān)心具體的類型。

那么如何定義一個(gè)List a類型呢?代碼如下

type List a = Empty | Node a (List a)

前面說到Tag可以攜帶已知類型,那么是否可以攜帶正在定義的這個(gè)類型呢?答案是肯定的!這就是類型的遞歸List a就是這樣一個(gè)帶有類型參數(shù)的遞歸類型,平時(shí)我們寫的數(shù)組,可以理解為如下代碼的語法糖

-- []
Empty

-- [1]
Node 1 Empty

-- [1, 2, 3]
Node 1 (Node 2 (Node 3 Empty))

同樣的思路,我們完全可以自己實(shí)現(xiàn)二叉樹等數(shù)據(jù)結(jié)構(gòu),有興趣的朋友不妨試試,官方文檔有相關(guān)章節(jié)可供參考

Counter with type

上一章[基礎(chǔ)篇]()我們講了Counter的實(shí)現(xiàn),代碼如下:

import Html exposing (..)
import Html.Events exposing (onClick)
import Html.App as App

type Msg = Increment | Decrement

update msg model = 
  case msg of 
    Increment -> 
      model + 1
    Decrement ->
      model - 1

view model =
  div []
    [ button [onClick Decrement] [text "-"]
    , text (toString model)
    , button [onClick Increment] [text "+"]
  ]

initModel = 3

main = App.beginnerProgram {model = initModel, view = view, update = update}

讓我們用剛剛學(xué)習(xí)的知識(shí)給以上代碼添加類型和類型注解

首先,我們有initModel這個(gè)數(shù)據(jù),它的類型是Int,不具備任何業(yè)務(wù)語義,讓我們定義一個(gè)類型別名Model來表示Counter的數(shù)據(jù)

type alias Model = Int

自然initModel的類型應(yīng)該為Model

initModel : Model
initModel = 3

update函數(shù)的類型簽名比較簡單,它接受消息Msg和當(dāng)前數(shù)據(jù)Model,返回新的數(shù)據(jù)Model:

update : Msg -> Model -> Model

view函數(shù)接受Model類型的數(shù)據(jù),返回什么呢?如果查閱div函數(shù)的文檔,你會(huì)發(fā)現(xiàn)返回的是一個(gè)帶有類型變量的類型Html msg。其實(shí)很好理解,因?yàn)殇秩窘缑娴暮瘮?shù)不僅要輸出Html,當(dāng)事件發(fā)生時(shí)還要輸出消息,輸出消息的類型,就是應(yīng)該賦給變量msg的類型,在Counter中消息的類型是Msg,因此:

view : Model -> Html Msg

完整代碼:

import Html exposing (..)
import Html.Events exposing (onClick)
import Html.App as App

type alias Model = Int

type Msg = Increment | Decrement

update : Msg -> Model -> Model
update msg model = 
  case msg of 
    Increment -> 
      model + 1
    Decrement ->
      model - 1

view : Model -> Html Msg
view model =
  div []
    [ button [onClick Decrement] [text "-"]
    , text (toString model)
    , button [onClick Increment] [text "+"]
  ]

initModel : Model
initModel = 3

main = App.beginnerProgram {model = initModel, view = view, update = update}
總結(jié)

類型的學(xué)習(xí)可能有些枯燥,但是非常重要。如果你了解redux,你會(huì)發(fā)現(xiàn)Union type簡直天生就是做action的料,比起redux在javascript中使用的字符串既簡潔又達(dá)意,甚至還可以嵌套組合,談笑風(fēng)生!高到不知道哪里去了!

下一章我們將把在線編輯器放到一邊,把Counter遷移到本地運(yùn)行,然后實(shí)現(xiàn)一個(gè)CounterList,在CounterList中,你會(huì)看到Elm是如何復(fù)用組件,以及為什么Elm被稱為理想的分形架構(gòu)。

各種架構(gòu)對(duì)比,可以參考Cycle.js作者Andre Staltz的文章

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/79638.html

相關(guān)文章

  • Elm入門實(shí)踐(一)——基礎(chǔ)

    摘要:由于內(nèi)容較多,計(jì)劃分四篇,大致內(nèi)容分布如下基礎(chǔ)篇介紹基礎(chǔ)。接下來讓我們補(bǔ)全這一部分在第行我們引入了模塊中函數(shù),可以理解為當(dāng)事件發(fā)生時(shí),它會(huì)輸出一個(gè)消息。我們有了數(shù)據(jù),具備行為的視圖,按行為改變數(shù)據(jù)的邏輯,卻沒有將它們粘合成一個(gè)應(yīng)用。 簡介 Elm 是一門專注于Web前端的純函數(shù)式語言。你可能沒聽說過它,但一定聽說過Redux,而Redux的核心reducer就是受到了Elm的啟發(fā)。 隨...

    junbaor 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.16 - 淺入淺出 JavaScript 函數(shù)式編程

    摘要:函數(shù)式編程,一看這個(gè)詞,簡直就是學(xué)院派的典范。所以這期周刊,我們就重點(diǎn)引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對(duì)編程語言的理解更加融會(huì)貫通一些。但從根本上來說,函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進(jìn)行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...

    csRyan 評(píng)論0 收藏0
  • 嘗試在JavaScript中構(gòu)建一個(gè)"Maybe"檢測器

    摘要:我的目的是確保所有引用的使用都是絕對(duì)安全的,編譯器會(huì)自動(dòng)進(jìn)行檢查。它導(dǎo)致了數(shù)不清的錯(cuò)誤漏洞和系統(tǒng)崩潰,可能在之后年中造成了十億美元的損失。這個(gè)函數(shù)將使用一個(gè)表示我們希望進(jìn)行轉(zhuǎn)換的函數(shù)參數(shù),并返回一個(gè)包含轉(zhuǎn)換結(jié)果的新參數(shù)。 翻譯原文出處:Building a Maybe in JavaScript 鄙人翻譯略差且略有出入,別見笑。 很多時(shí)候我們會(huì)碰到:Uncaught TypeError...

    bingo 評(píng)論0 收藏0
  • 2017值得一瞥的JavaScript相關(guān)技術(shù)趨勢(shì)

    摘要:值得一瞥的相關(guān)技術(shù)趨勢(shì)從屬于筆者的前端入門與工程實(shí)踐,推薦閱讀我的前端之路工具化與工程化獲得更多關(guān)于年前端總結(jié)。的不少開發(fā)者都是的粉絲,他們的以及都是基于構(gòu)建的。 2017值得一瞥的JavaScript相關(guān)技術(shù)趨勢(shì)從屬于筆者的Web 前端入門與工程實(shí)踐,推薦閱讀2016-我的前端之路:工具化與工程化獲得更多關(guān)于2016年前端總結(jié)。本文主要內(nèi)容翻譯自,筆者對(duì)于每個(gè)條目進(jìn)行了些許完善。本文...

    davidac 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

ZHAO_

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<