0

0

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

php中文网

php中文网

发布时间:2016-06-24 11:15:39

|

1263人浏览过

|

来源于php中文网

原创

记得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),直接的表明了它的用途:构建属于该类型的值

超会AI
超会AI

AI驱动的爆款内容制造机

下载

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

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

相关文章

HTML速学教程(入门课程)
HTML速学教程(入门课程)

HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

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

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

616

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

194

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

91

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

20

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

54

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

15

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

598

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

56

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
微信小程序开发之API篇
微信小程序开发之API篇

共15课时 | 1.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 835人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号