Haskell学习心得

Haskell学习心得

话说程序员要每年学一门编程语言.2020年,目标Haskell.

特性

  • 柯里化
    Haskell的函数,只有单参数函数.它的多参数函数,其实只是返回了另一个函数.
    所以在进行部分参数应用的时候,会非常的自然.
  • 运算符
    所有的运算符也是函数,和函数不同的是,运算符的结合性和优先级可以自定义.函数的结合性和优先级是固定的.
  • 强类型和类型推导
    定义函数时,可以声明类型,也可以不声明类型.如果不声明类型,Haskell会根据上下文推导出来类型.它的自动推导功能十分强大.
  • 函数调用不需要括号,参数之间用空格分隔
    和其他语言用括号和逗号的风格不同,Haskell里面调用函数通过空格分隔函数名和参数,也通过空格分隔多个参数.配合柯里化,函数应用符$,可以实现另人惊艳的效果,比如其他语言中f(g(h(x)))这样的调用,可以写成f $ g $ h x,将代码的嵌套风格变成了扁平的风格.
  • 支持模式匹配
    十分方便解构数据,判断类型,代码写起来也非常优雅.
  • 支持lambda表达式
  • 不可变变量
    变量一旦定义不可重新赋值.
  • 前缀运算符,中缀运算符,后缀运算符,混合位置运算符
    前缀运算符用中缀形式调用.中缀运算符可以使用前缀形式调用.
    if then else是一个混合位置运算符
  • 惰性求值
    在真正需要的时候才进行计算,很容易定义无限列表.
  • 隔离纯函数和非纯函数
    Haskell中严格区分纯与不纯函数.一旦一个函数变成不纯函数,那么它的调用者也是不纯函数.从纯函数取结果和从不纯函数取结果的方式不一样.
  • 函数调用符$
    这个可以实现f(g(x))写成f $ g x这样的效果.
  • 管道运算符|>
    可以实现参数写在前面,函数写在后面的效果.
    比如text |> lines |> map (++"!!!")的语义为,将文本text按换行符分隔,得到一个列表,然后列表中每个字符串后面拼接3个感叹号.
  • 类型,类型类,kind
    如果拿java作比喻的话,Haskell中的类型(type)类似于java的class
    Haskell中的类型类(typeclass)类似于java的interface(可以定义默认实现的那种)
    Haskell中的kind,就是类型的类别(好吧,不理解没关系,就是个概念而已).
  • 类型构造器和数据构造器
    Haskell中区分类型构造器和数据构造器.
    在java中构造器必须和类型名称相同.Haskell中一个类型可以有多个数据构造器.
  • 代码结构
    Haskell由多个模块组成.一个模块由模块导入,模块和导出声明,类型定义,函数定义,运算符定义,变量定义组成.函数由函数声明和函数体组成.函数体由表达式组成.Haskell中没有语句.最后一个表达式的值就是函数的返回值.
  • 列表生成器
    类似于python中的列表生成器,python应该是借鉴Haskell这类语言的.
  • 容器与盒子
    虽然没有明确的定义,但是一般我们把参数化类型当成容器.把参数化类型构造出的类型的值当做盒子.
  • Functor,Applicative,Monad
    这些类型类,定义了相关的处理盒子的函数.因为非纯函数操作,异常处理操作等,Haskell会将它们的值装进盒子,定义一系列操作盒子的函数,可以方便调用非纯函数.

心得

  • 思维方式的改变.命令式编程,我们告诉程序问题如何解决.函数式编程我们告诉程序问题是什么.
  • 函数参数都是基于位置的,不支持命名参数和默认参数.这对代码的可读性是一个非常大的挑战.从一个函数的声明中,我们只能看到类型信息.
    一门语言的函数调用形式如何设计,其实是需要很讲究的.柯里化形式有它的优势(简洁,可扁平化,可实现管道风格-相当于oop里面的链式调用吧,易实现DSL),也有它的劣势(需要记住各位置填什么参数.想想用shell命令时经常弄错参数位置的情形吧).从工程角度看,基于位置的方式可读性会差很多.
  • Haskell中各种运算符,比如>>=,>>>,>>,<=<,=<<,<$>,<*>,*>,|>,<|>,<*,,它们的语义太丰富,晦涩难懂.读源代码的时候,大脑需要处理太多信息.如果再加点料,配上一些高阶函数,那"酸爽",谁用谁知道.
    如果程序的简洁性需要以可读性为代价,那么我宁愿不那么简洁.
  • 副作用的处理.Haskell中强制隔离pure操作和IO操作.这个思想非常好,用于java中也获益匪浅.可以大大提高代码的易测试性,降低耦合性.
  • 异常处理.有一种异常处理思想深得我心,let it crash.这种思想认为,程序出异常了,大部分情况下我们并不需要在方法里面捕获它,我们只需要不管它,让它一直往上抛即可.Haskell喜欢用Maybe,Either来表示异常.我对这种不能打印异常栈的处理方式深表怀疑.
  • 命名空间.在java中,不推荐import *.当然,haskell里面也可以import SomeModule (f1,f2)这样解决.但是,不同模块的函数名冲突了,就需要起别名了.
  • 多行字符串.貌似没有看到关于Haskell中处理多行字符串的方案.
  • 惰性求值与栈溢出.容易写出看上去没啥问题,实际上会栈溢出的代码.
  • Haskell中有专门用于写编译器的库.嗯…这个用来创造自己的编程语言,真的太棒了.
  • 有些经典算法的描述,是通过命令式方式描述的.要用haskell实现,可能要费一些脑细胞.
  • 暂时想到这么多了,打算复习并整理一遍数据结构和算法.用haskell实现,体验一下.如果感觉还不错,后面我就是haskell粉了.

你可能感兴趣的:(haskell,其他)