1

Try to understand map, and write one to test it,

func map<A, B>(x: A?, f: A -> B) -> B? {
  if let x1 = x {
    return f(x1)
  }
  return nil
}

let test1 = [1, 2, 3, 4]
println(test1)
let test2 = map(test1, { $0 + 1 })
println(test2)

let test3: [Int?] = [5, nil, 7, 8]
println(test3)//[{Some "aaa"}, {Some "bbb"}, nil, {Some "ccc"}]
let test4 = map(test3, { $0 + 1 })
println(test4) //"Optional(0x00007fb7ea61e190)"

but why the test4 cannot output the value, just display a pointer?

GoZoner
  • 67,920
  • 20
  • 95
  • 145
A.C
  • 191
  • 1
  • 2
  • 10

1 Answers1

5

Pointer Explanation

What’s happening here is you’re hitting an implicit conversion of arrays to pointers, that is there for C compatibility purposes.

Ordinarily, you wouldn’t be able to add 1 to an array. I mean, what would it mean to do that? However, Swift does have an implicit conversion of arrays to pointers, so that you can pass arrays into C functions:

import Darwin
// prints out “hello” using a standard C function that takes a char*
puts([104,101,108,108,111,0])

And you can add integers to pointers (to do good ol’ pointer arithmetic):

// x will be an UnsafePointer<Int>
let x = [1,2,3] + 1

Now, to stop you doing this by accident, this is only supposed to work on literals:

let a = [104,101,108,108,111,0]
// error: binary operator '+' cannot be applied to operands of type '[Int]' and 'Int'
let x = a + 1

But when using generic functions, this conversion still happens (possibly unintentionally).

Issues with your Map

It looks from your definition like you’re trying to write a version of map for optionals – that is, something that takes an optional, and maps the contents if it has some.

But then, instead of mapping optionals, you’re using it to on sequences. In fact in your code snippet, on the line let test2 = map(test1, { $0 + 1 }), you aren’t calling your map at all – you’re calling the standard library version that takes a sequence (and returns an array). Try putting an assert(false) in there – you’ll see it’s not being called the first time around.

Map for optionals and map for arrays are very conceptually similar. This is because optionals and arrays are both “functors” – the name for things that can be “mapped over”. Think of them both as containers – types that contain other types. In the case of optionals, they contain a value or not. In the case of arrays, they contain any number of values. But in both cases, it’s useful to have a function that you apply to the “contents” while leaving them within the “container”.

Consider the following code. It has two maps, for sequences and optionals, and applys them in turn. The last example seems to be what you were looking for in your question’s last case – mapping plus-one on each member of an array of optionals. This is really two maps, one within the other.

func mymap<A, B>(x: A?, transform: A -> B) -> B? {
    println("map for optionals called!")
    if let x1 = x {
        return transform(x1)
    }
    return nil
}

func mymap<S: SequenceType, T>(source: S, transform: S.Generator.Element -> T) -> [T] {
    println("map for sequences called!")
    var result: [T] = []
    for x in source {
        result.append(transform(x))
    }
    return result
}

let test1 = [1, 2, 3, 4]
// prints "map for sequences called!"
let test2 = mymap(test1, { $0 + 1 })
println(test2) // prints

let test3: Int? = 5
// prints "map for optionals called!"
let test4 = mymap(test3, { $0 + 1 })
println(test4) // Optional(6)

let test5: [Int?] = [1, nil, 3, 4]
// prints "sequences called" followed by 4 "optionals called"
let test6 = mymap(test5) { mymap($0) { i in i + 1 } }
println(test6) // [Optional(2), nil, Optional(4), Optional(5)]
Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
  • 1,Your mean the map function I write is different from the Swift build-in function - map? – A.C Mar 09 '15 at 04:26
  • 2,How can I call my map function to apply to test2? – A.C Mar 09 '15 at 04:29
  • 3,A litter bit hard to understand "sequences" and “functors”. – A.C Mar 09 '15 at 04:38
  • 1. Your `map` was equivalent to _one_ of the Swift standard library’s maps – but `map` is overloaded, there are two. One that takes a `SequenceType` and the other takes an `Optional. Which one is chosen is based on what you pass in – whether it’s compatible (can’t pass a non-sequence into a version of map that takes an optional) plus precedence rules if there’s multiple possible matches. – Airspeed Velocity Mar 09 '15 at 11:32
  • 2. You can force calling your function using `Modulename.Functionname` but only if it’s compatible. 3. Try reading [this](http://nshipster.com/swift-collection-protocols/) about sequences and collections. Functor is a little harder – probably best to ignore that for now, but bear in mind when you hear people talk about “functors” (and “monads”) that it’s not as scary as it seems – it just has to do with “containers" like arrays and optionals that can have a “map” (or “flatMap”) function. Eventually if you bump into them enough, you’ll get what they are. – Airspeed Velocity Mar 09 '15 at 11:35