`Maybe` handling in Matrix manipulation in Elm
I like your code a lot more than the original! It is definitely cleaner and more obvious than the first example you gave. However, there still seems to be a process you’re repeating — get value from array, pattern match on it, update array — that you can still factor out. (The original code is guilty of this, too.)

I tried to rewrite your function in a matter that avoids this, and my code’s at the bottom; see if you find it more readable. But first, some stylistic advice on writing Elm:


Generally, instead of writing things like Array.Array, it's useful to expose the type name from the data structure package you're using. Also, type parameters don’t need parentheses around them (except for grouping).

So you can rewrite:

type alias Board = Array.Array (Array.Array (Slot))


to

import Array exposing (Array)

type alias Board = Array (Array Slot)


which I think is a bit more Elm-y.
A useful design guideline (for packages, but  it’s a good idea for code in general): the data structure is always the last argument. You’ve reordered them from your first example, but the original order was there for a good reason: if your types look like

f : (extra params) -&gt; Container -&gt; Container


you can partially apply your function and end up with:

f "extra" "arguments" : Container -&gt; Container


which is very useful for function composition and piping: often you want to take a Container and pipe it through a bunch of Container -&gt; Container functions, like so:

result =
    initialContainerValue
    |&gt; f "hello" "world"
    |&gt; someOtherStep
    |&gt; f "oak" "fir"

The Elm style guide contains some more recommendations that could apply to your code, but they’re more subjective. The two big ones I could think of have to do with whitespace. 


Always have 2 empty lines between top-level declarations.
The examples in the guide have single empty lines between case branches, too.



My version

{-| Apply a function at the given index in the array.

     applyAt 2 negate (fromList [50, 60, 70]) == fromList [50, 60, -70]
-}
applyAt : Int -&gt; (a -&gt; a) -&gt; Array a -&gt; Array a
applyAt i f array =
    case Array.get i array of
        Nothing -&gt;
            array

        Just a -&gt;
            Array.set i (f a) array


{-| Update a slot: the given player occupies it, but only if it's empty. -}
setSlot : Player -&gt; Slot -&gt; Slot
setSlot player slot =
    case slot of
        Empty -&gt;
            PlayedBy player

        s -&gt;
            s


{-| Update a slot somewhere in a board. -}
setPosition : Position -&gt; Player -&gt; Board -&gt; Board
setPosition (row, column) player =
    applyAt row
        (applyAt column
            (setSlot player))