zoukankan      html  css  js  c++  java
  • haskell类型

    一、源文件

    介绍这个主要是因为下文很多代码写在源文件中,然后从ghci加载源文件进行测试。

    创建一个文本文件,在其中输入,并保存为add.hs文件

    -- file: add.hs
    add x y = x - y

    打开ghci,加载刚才的文件(假设文件目录为e:haskelladd.hs),命令如下

    ghci> :cd e:haskell
    ghci> :load add.hs
    ghci> add 2 1

    二、语言特性

    1. 延迟计算

    表达式的值在需要用到的时候才被计算,比如在一个文本文档中输入如下,并保存为lazy.hs

    -- file: lazy.hs
    add x y = if left || right then x + y else x -y
    left = True
    right = length [1..] > 0

    然后加载这个文件,并执行 add 2 1,你会发现结果为3,而不是一直等待计算结果,说明right的值并没有被计算出来。在很多其他语言中(如C#),逻辑或or被特殊处理,从而在左分量为真的时候对右分量短路(short-circuits),而haskell中,(||)运算符只是一个普通的函数,并由于其延迟计算的特性,导致左分量为真的时候,右分量不被计算出来。当然了,haskell中也可以写出短路的逻辑或函数

    myOr l r = if l then l else r

    haskell中还有一个称作守卫表达式的东东,上面说的myOr函数等价于

    -- file: myOr.hs
    myOr l r | l = l
    myOr l r = r

    2. 类型

    a) 函数类型

    我们看take函数的类型

    ghci> :type take
    take :: Int -> [a] -> [a]

    符号->是右结合的,即,类型说明等价于

    take :: Int -> ([a] -> [a])

    b)代数数据类型

    定义一个新的数据类型

    -- file: Object.hs
    data ObjectProperty = Object Int String [String]
                          deriving (Show)

    这个类型ObjectProperty与三元组(Int, String, [String])的元素相同,然而haskell认为它们类型不相同。如果要定义一个ObjectProperty类型变量,

    ghci> let object = Object 0 "i" ["j", "k"]
    ghci> :type it
    it :: ObjectProperty
    ghci> :type Object
    Object :: Int -> String -> [String] -> ObjectProperty

    分析: Object是值(数据)构造器,ObjectProperty是对象类型,当然,也可以将对象类型与值构造器写成相同的,如

    data Object = Object Int String [String]

    然而两者仅仅是名称相同而已。

     对于Object的元素分别为Int,String等类型,还可以自定义这些类型的同义类型,如下

    -- file: Object.hs
    type ObjectId = Int
    type ObjectName = String
    type ObjectFields = [String]
    data Object = Object ObjectId ObjectName ObjectFields

    其实跟C++中的typedef关键字类似。

    可以查看值构造器Object的类型(是一个函数)

    ghci> :type Object
    Object :: ObjectId -> ObjectName -> ObjectFields -> Object

     由于Object类型中元素是匿名的,可以通过匹配来获取元素值,例如

    ghci> let object = Object 0 "a" ["b", "c"]
    ghci> let Object x y z = object
    ghci> x
    0
    ghci> :type x
    x :: ObjectId

    c)枚举类型

    -- file: Roygbiv.hs
    data Roygbiv =     Red
                    |  Orange
                    |  Yellow
                    |  Green
                    |  Blue
                       deriving (Eq, Show)

    其中Red、Orange等都为值构造器

    d) 记录类型

    前面简单介绍过模式匹配。比如想内窥一下Object(前文介绍的自定义代数数据类型)的内部元素,则可以使用模式匹配,我们这次定义一个函数来获取某个元素

    getId (Object id _ _) = id
    getName (Object _ name _) = name
    getFields (Object _ _ fields) = fields

    然而这种方法还是显得代码大块,看起来不爽。

    可以定义记录类型,如下

    -- file: Object.hs
    data Object = Object {
        oid :: Int,
        oname :: String,
        ofields :: [String]
        } deriving (Show)

    这个类型定义其实跟下面的形式几乎相同

    -- file: Object.hs
    data Object = Object Int String [String]
                         deriving (Show)
    
    getId :: Object -> Int
    getId (Object id _ _) = id
    
    getName :: Object -> String
    getName (Object _ name _) = name
    
    getFields :: Object -> [String]
    getFields (Object _ _ fields) = fields

    加载上面那个文件时,依然可以向以前那么使用Object类型

    ghci> let object = Object 1 "az" ["b"]

    或者如下使用

    ghci> -- order of elements can be varied
    ghci> let object = Object{oid = 10, ofields = ["i"], oname="str"}

    e)参数化类型

    跟C#中的泛型类似。比如定义一个类型MyMaybe如下(注意与Prelude模块中的Maybe区分,虽然功能类似)

    -- file: Maybe.hs
    data MyMaybe a = MyJust a
                   | MyNothing

    这里a就是参数化类型,a可以是String或者Int等,还可以是MyMaybe类型,即嵌套

    ghci> let a = MyJust 1
    ghci> let b = Just a
    ghci> :type b
    b :: Num a => Maybe (MyMaybe a)

    f)递归类型

    haskell中的List类型与C#中的不同,它是一个递归类型,如下

    -- file: MyList.hs
    data MyList a = Cons a (MyList a)
                  |  Empty
                     deriving (Show)

    这样设计,使得对其进行递归计算方便。

     比如获取List的首项,可以写成如下

    -- append to the former MyList.hs file end
    
    x = Empty
    y = Cons 1 x
    
    myHead (Cons i j) = i
    myHead Empty = error "MyList.myHead: empty list"

    这里对Empty获取首项会抛出一个错误,这样处理还是可以的,我们不能返回Empty,否则跟myHead的第一个计算式的返回类型不同(第一个计算式返回类型为a,而Empty类型为MyList a)。不过,如果结合Maybe类型,或者上面介绍的MyMaybe类型,则可以避免抛出错误,从而使得代码更好看些。处理如下

    myHead (Cons i j) = MyJust i
    myHead Empty = MyNothing
  • 相关阅读:
    android之Fragment(官网资料翻译)
    Java获取当前时间的年月日方法
    Android Fragment Base
    Java JNI初探
    PHP 初学之登录查询小case
    PHP 初学
    tomcat:run和tomcat7:run的区别,以及Apache Tomcat Maven Plugin 相关
    Intellij IDEA:maven的本地仓库问题
    Java 构造方法的执行过程(猜测)
    PHP wamp server问题
  • 原文地址:https://www.cnblogs.com/sjjsxl/p/5413757.html
Copyright © 2011-2022 走看看