Haskell中的数组定义了类型(不是数据)

时间:2015-05-31 16:22:14

标签: arrays haskell

type Array a = Int -> a

emptyArray :: Array a
emptyArray i =
  error ("Access to non-initialized index " ++ show i)

putIndex :: Array a -> Int -> a -> Array a
putIndex ar i v = ar'
 where ar' j | j==i      = v
             | otherwise = ar j

getIndex :: Array a -> Int -> a
getIndex a i = (a i)

我不理解emptyArrayputIndex功能。 问题是:

  • ar'
  • 的类型是什么
  • 什么时候ar'模式匹配?
  • 何时是j==i
    • v属于a或?在这种情况下,它不会返回数组。
  • 在= = ar j
  • 中会发生什么
  • 为什么getIndex (putIndex emptyArray 1 3) 2会产生错误
    • getIndex (putIndex emptyArray 1 3) 1返回3似乎很清楚。

2 个答案:

答案 0 :(得分:6)

我不会直接回答您的所有问题,而是会尝试解释Array a类型背后的基本原理。

数组可以被认为是具有特定属性的数据结构,即给定索引它可以返回与该索引关联的值。这意味着我们可以通过描述与特定索引关联的值来表征数组,这听起来非常像将输入(索引)映射到输出(该索引处的值)的函数。因此,如果您不想知道长度或哪些索引有效,则可以认为数组与函数没有区别。这是一个相当有限的数组定义,但作为一个学习练习,重要的是要看看如何通过考虑最重要的操作来将数据结构转换为函数。

  

ar'

的类型是什么

查看类型签名:

putIndex :: Array a -> Int -> a -> Array a
putIndex    ar         i      v  = ar'

所以ar :: Array ai :: Intv :: a , and ar':: Array a`。

  

ar'模式何时匹配?

我假设您的意思是何时使用ar'的定义。 ar'Array a,这意味着它是一个函数Int -> a。这意味着只要在其上调用getIndex就会使用它。

  

何时是j == iv的类型是a?在这种情况下,它不会返回数组

仔细查看putIndex的定义。 ar'putIndex的返回值,而不是vvar'j == i的返回值。从v的类型签名可以看出,a的类型为putIndexputIndex是一个增强现有功能ar的功能,首先为i == j添加检查。

  

otherwise = ar j

中会发生什么

如果j /= i,则不会返回v(新值与索引i相关联),而是查找原始索引j中的值ar。这可能更明确地说明为

putIndex originalArray indexToSet newValue = newArray
    where
        newArray j
            | j == indexToSet = newValue
            | otherwise       = getIndex originalArray j
  

为什么getIndex (putIndex emptyArray 1 3) 2会产生错误?

基本上,您可以将索引查找转换为一堆嵌套的if语句:

putIndex emptyArray i0 x0  ==>  \i -> if i == i0
                                    then x0
                                    else emptyArray i

putIndex (
    putIndex emptyArray i0 x0
    ) i1 x1                ==>  \i -> if i == i1
                                    then x1
                                    else if i == i0
                                            then x0
                                            else emptyArray i

putIndex (
    putIndex (
        putIndex emptyArray i0 x0
        ) i1 x1
    ) i2 x2                ==>  \i -> if i == i2
                                    then x2
                                    else if i == i1
                                            then x1
                                            else if i == i0
                                                    then x0
                                                    else emptyArray i

依此类推,为每个新if-then-else添加一个putIndex的新图层。对于您的具体示例

putIndex emptyArray 1 3  ==>  \i -> if i == 1
                                    then 3
                                    else emptyArray i

然后

getIndex (putIndex emptyArray 1 3) 2

等同于表达式

if 2 == 1 then 3 else emptyArray 2

答案 1 :(得分:4)

  1. ar' :: Int -> a
  2. 始终(只有putIndex ar i v模式,这将始终匹配)
  3. 如果你在索引j == i调用结果函数/数组,那么
  4. 以及i(来自调用i的{​​{1}} - putIndex是参数对于本地函数j
  5. 否则使用数组/函数ar'(您看到只在索引ar更改数组
  6. i = j中的每个索引都会产生错误 - emptyArray您在putIndex更改了此信息,但之后您将其调用i = 1,因此它将使用i= 2的定义emptyArray(上面的otherwise案例),这是错误
  7. 与5中的情况相同,但在此您使用i = 1putIndex至3
  8. 进行调用

    也许你这样理解:emptyArray是一个始终errors

    的函数

    然后你可以使用putIndex来获得一个新的数组/函数,它的第一个参数与这个参数的作用相同 - 仅在索引i它现在将返回{{1} } - 对于所有其他indizes v,它将返回i index i中的旧函数/数组)。

    ar i实际上只是在索引中为调用函数/数组

    以下是getIndex出错的原因:

    getIndex (putIndex emptyArray 1 3) 2

    但对getIndex (putIndex emptyArray 1 3) 2 = (putIndex emptyArray 1 3) 2 { inside putIndex you get i = 1, v = 3 and j = 2 here } = emptyIndex 2 = error ... 而言:

    getIndex (putIndex emptyArray 1 3) 1