目录
类型注解
基本类型和List
基本类型
List
类型别名
Union Types
Type variables
Counter with type
总结
首页 web前端 html教程 Elm入门实践--类型篇_html/css_WEB-ITnose

Elm入门实践--类型篇_html/css_WEB-ITnose

Jun 24, 2016 am 11:15 AM

记得Facebook曾经在一次社区活动上说过,随着他们越来越多地使用Javascript,很快就面临了曾经在PHP上遇到的问题:这东西到底是啥?

动态语言就像把双刃剑,你可以爱死它的灵活性,也可能因为一个小的疏忽而损失惨重。Elm选择了静态强类型,这通常也是多数函数式语言的选择,没有了OO语言中 类的概念,强大的类型系统负责解决一切“这是什么?”的问题

类型注解

也可以叫做类型签名,Elm 使用冒号 :来注明类型,在Hello world的基础上,让我们分别定义一个变量和函数,并且注明类型

import Html exposing (..)import Html.Attributes exposing (..)elm : Stringelm = "elm"sayHello : String -> StringsayHello name =   "Hello, " ++ namemain =  div [class "hello"]     [ span [] [text (sayHello elm)]    ]
登录后复制

尝试将elm的值”elm”改为数字,看看会发生什么?

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:    StringBut I am inferring that the definition has this type:    number
登录后复制

编译器发现了错误,并且能够定位到具体的行数。

如果不声明类型呢?如果注释掉类型注解

import Html exposing (..)import Html.Attributes exposing (..)--elm : Stringelm = 6--sayHello : String -> StringsayHello name =   "Hello, " ++ namemain =  div [class "hello"]     [ span [] [text (sayHello elm)]    ]
登录后复制

重新编译,还是会报错,只是错误信息变了,这次是第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:    StringBut it is:    number
登录后复制

即使没有显式的类型注解,Elm的类型推导系统也会发挥作用,此处通过类型推导认为 sayHello函数的参数应该是字符串,但是传入了数字,因此报错。

对比两次不同的错误提示可以看出,类型注解能让编译器更准确地发现和定位错误。随着学习的深入你会慢慢喜欢上类型系统带来的安全感:如果编译失败,明确的提示能帮助你快速定位问题。而只要编译通过,程序就一定能运行。

基本类型和List

基本类型

基本类型和多数语言是类似的,无非就是 String, Char, Bool Int, Float,可以参考官网的 literals。需要注意在Elm中, String必须用双引号,单引号是用来表示 Char的,字符串单引号党需要适应一下。

List

严格来说List并不是类型,它的类型是 List a,其中的 a被称作 类型变量,这是因为List作为容器,它可以装String,Int,或者什么都不装,因此类型必须是动态的:

> [ "Alice", "Bob" ][ "Alice", "Bob" ] : List String> [ 1.0, 8.6, 42.1 ][ 1.0, 8.6, 42.1 ] : List Float> [][] : List a
登录后复制

关于 类型变量后面会继续讨论,在这里我们只需要记住一点: List不是类型,类似List String这样的才是

由于参数只有一个,Elm的List只能容纳单一类型的元素,和Javascript来者不拒的List不同,下面这样的是会被编译器发现并报错的:

list = [1, "a"]
登录后复制

类型别名

类型别名用于组合或复用已知的类型,比如

type alias Name = Stringtype alias Age = Int  type alias User = {name: Name, age: Age}user : Useruser =  { name = "Zhang zhe", age = 89 }  setUserName : String -> User -> UsersetUserName name user = {user | name = name}
登录后复制

它不仅可以让基本类型具备业务语义,还可以为复杂的数据结构组合出合适的、语义化的类型。没有别名的话,setUserName的类型签名就得写成下面这样……一坨:

setUserName : String -> {name: String, age: Int} -> {name: String, age: Int}
登录后复制

Union Types

Union type 是Elm类型系统中最重要的部分之一,它用来表示一组可能的值,每个值叫做一个 Tag,如下:

type Bool = True | Falsetype User = Anonymos | Authed
登录后复制

其中 True和 False, Anonymos和 Authed都是 Tag名( 注意Tag不是Type)。看起来很像枚举?不只这样,Union type强大的地方在于: Tag可以携带一组已知类型。上面的代码我们虽然能区分两类用户,但并不能获取认证用户的名称,这时候就可以用已知类型结合Tag表达:

type User = Anonymos | Authed String
登录后复制

当我们创建Union type的时候,实际上为每个 Tag都创建了相应的 值构造器:

> type User = Anonymous | Authed String> AnonymousAnonymous : User> AuthedAuthed : String -> User
登录后复制

不带其它信息的Anonymous可以直接作为 值使用(想想 True和 False),而带有已知类型的Authed实际上是一个函数,它接受String,返回User类型:

users : List Userusers = [  Anonymous,   Authed "Kpax"]
登录后复制

在Haskell中没有Tag的叫法,相似的东西就叫 值构造器(value constructor),直接的表明了它的用途:构建属于该类型的值

Tag还可以被解构:

getAuthedUserName : User -> StringgetAuthedUserName user =  case user of     Anonymous ->      ""    Authed name ->      name
登录后复制

这个函数返回Authed用户的名称,如果是Anonymous用户则返回空字符串。

完整的可在在线编辑器中执行的代码如下:

import Html exposing (..)import Listtype User = Anonymous | Authed Stringusers : List Userusers = [  Anonymous,   Authed "Kpax",  Authed "qin"]getAuthedUserName : User -> StringgetAuthedUserName user =  case user of     Anonymous ->      ""    Authed name ->      name      main =  div [] (List.map (text << getAuthedUserName) users)
登录后复制

text << getAuthedUserName使用了Elm中的 <<操作符实现两个函数的compose,类似于lodash中的 _.flowRight函数

Type variables

上面已经提到了 List a类型,其中 a即类型变量,表示一个当前还不确定的类型,类似于面向对象编程中泛型的概念

map函数的类型签名也使用了类型变量:

map : (a -> b) -> a -> b
登录后复制

这使得我们调用map函数 map userToString user时,只要保证user是User类型即可,map函数并不关心具体的类型。

那么如何定义一个 List a类型呢?代码如下

type List a = Empty | Node a (List a)
登录后复制

前面说到 Tag可以携带已知类型,那么是否可以携带正在定义的这个类型呢?答案是肯定的!这就是类型的 递归, List a就是这样一个带有类型参数的递归类型,平时我们写的数组,可以理解为如下代码的语法糖

-- []Empty-- [1]Node 1 Empty-- [1, 2, 3]Node 1 (Node 2 (Node 3 Empty))
登录后复制

同样的思路,我们完全可以自己实现二叉树等数据结构,有兴趣的朋友不妨试试,官方文档有 相关章节可供参考

Counter with type

上一章[基础篇]()我们讲了Counter的实现,代码如下:

import Html exposing (..)import Html.Events exposing (onClick)import Html.App as Apptype Msg = Increment | Decrementupdate msg model =   case msg of     Increment ->       model + 1    Decrement ->      model - 1view model =  div []    [ button [onClick Decrement] [text "-"]    , text (toString model)    , button [onClick Increment] [text "+"]  ]initModel = 3main = App.beginnerProgram {model = initModel, view = view, update = update}
登录后复制

让我们用刚刚学习的知识给以上代码添加类型和类型注解

首先,我们有 initModel这个数据,它的类型是 Int,不具备任何业务语义,让我们定义一个类型别名 Model来表示Counter的数据

type alias Model = Int
登录后复制

自然 initModel的类型应该为 Model

initModel : ModelinitModel = 3
登录后复制

update函数的类型签名比较简单,它接受消息 Msg和当前数据 Model,返回新的数据 Model:

update : Msg -> Model -> Model
登录后复制

view函数接受 Model类型的数据,返回什么呢?如果查阅 div函数的 文档,你会发现返回的是一个带有类型变量的类型 Html msg。其实很好理解,因为渲染界面的函数不仅要输出Html,当事件发生时还要输出 消息,输出消息的类型,就是应该赋给变量 msg的类型,在 Counter中消息的类型是 Msg,因此:

view : Model -> Html Msg
登录后复制

完整代码:

import Html exposing (..)import Html.Events exposing (onClick)import Html.App as Apptype alias Model = Inttype Msg = Increment | Decrementupdate : Msg -> Model -> Modelupdate msg model =   case msg of     Increment ->       model + 1    Decrement ->      model - 1view : Model -> Html Msgview model =  div []    [ button [onClick Decrement] [text "-"]    , text (toString model)    , button [onClick Increment] [text "+"]  ]initModel : ModelinitModel = 3main = App.beginnerProgram {model = initModel, view = view, update = update}
登录后复制

总结

类型的学习可能有些枯燥,但是非常重要。如果你了解redux,你会发现Union type简直天生就是做action的料,比起redux在javascript中使用的字符串既简洁又达意,甚至还可以嵌套组合,谈笑风生!高到不知道哪里去了!

下一章我们将把在线编辑器放到一边,把Counter迁移到本地运行,然后实现一个CounterList,在CounterList中,你会看到Elm是如何复用组件,以及为什么Elm被称为理想的 分形架构。

各种架构对比,可以参考Cycle.js作者Andre Staltz的 文章 `elm

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

&gt; gt;的目的是什么 元素? &gt; gt;的目的是什么 元素? Mar 21, 2025 pm 12:34 PM

本文讨论了HTML&lt; Progress&gt;元素,其目的,样式和与&lt; meter&gt;元素。主要重点是使用&lt; progress&gt;为了完成任务和LT;仪表&gt;对于stati

HTML容易为初学者学习吗? HTML容易为初学者学习吗? Apr 07, 2025 am 12:11 AM

HTML适合初学者学习,因为它简单易学且能快速看到成果。1)HTML的学习曲线平缓,易于上手。2)只需掌握基本标签即可开始创建网页。3)灵活性高,可与CSS和JavaScript结合使用。4)丰富的学习资源和现代工具支持学习过程。

&lt; datalist&gt;的目的是什么。 元素? &lt; datalist&gt;的目的是什么。 元素? Mar 21, 2025 pm 12:33 PM

本文讨论了html&lt; datalist&gt;元素,通过提供自动完整建议,改善用户体验并减少错误来增强表格。Character计数:159

&lt; meter&gt;的目的是什么。 元素? &lt; meter&gt;的目的是什么。 元素? Mar 21, 2025 pm 12:35 PM

本文讨论了HTML&lt; meter&gt;元素,用于在一个范围内显示标量或分数值及其在Web开发中的常见应用。它区分了&lt; meter&gt;从&lt; progress&gt;和前

视口元标签是什么?为什么对响应式设计很重要? 视口元标签是什么?为什么对响应式设计很重要? Mar 20, 2025 pm 05:56 PM

本文讨论了视口元标签,这对于移动设备上的响应式Web设计至关重要。它解释了如何正确使用确保最佳的内容缩放和用户交互,而滥用可能会导致设计和可访问性问题。

&lt; iframe&gt;的目的是什么。 标签?使用时的安全考虑是什么? &lt; iframe&gt;的目的是什么。 标签?使用时的安全考虑是什么? Mar 20, 2025 pm 06:05 PM

本文讨论了&lt; iframe&gt;将外部内容嵌入网页,其常见用途,安全风险以及诸如对象标签和API等替代方案的目的。

HTML,CSS和JavaScript的角色:核心职责 HTML,CSS和JavaScript的角色:核心职责 Apr 08, 2025 pm 07:05 PM

HTML定义网页结构,CSS负责样式和布局,JavaScript赋予动态交互。三者在网页开发中各司其职,共同构建丰富多彩的网站。

了解HTML,CSS和JavaScript:初学者指南 了解HTML,CSS和JavaScript:初学者指南 Apr 12, 2025 am 12:02 AM

WebDevelovermentReliesonHtml,CSS和JavaScript:1)HTMLStructuresContent,2)CSSStyleSIT和3)JavaScriptAddSstractivity,形成thebasisofmodernWebemodernWebExexperiences。

See all articles