Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Rather than starting by trying to fit <code>map</code> in somehow, consider how you might simplify and generalize your current function. Starting from this:</p> <pre><code>dotProduct :: [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] dotProduct [] _ = [] dotProduct [(x,y)] z = [(x*z,y)] dotProduct ((x,y):xys) z = (x*z,y):dotProduct (xys) z </code></pre> <p>First, we'll rewrite the second case using the <code>(:)</code> constructor:</p> <pre><code>dotProduct ((x,y):[]) z = (x*z,y):[] </code></pre> <p>Expanding the <code>[]</code> in the result using the first case:</p> <pre><code>dotProduct ((x,y):[]) z = (x*z,y):dotProduct [] z </code></pre> <p>Comparing this to the third case, we can see that they're identical except for this being specialized for when <code>xys</code> is <code>[]</code>. So, we can simply eliminate the second case entirely:</p> <pre><code>dotProduct :: [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] dotProduct [] _ = [] dotProduct ((x,y):xys) z = (x*z,y):dotProduct (xys) z </code></pre> <p>Next, generalizing the function. First, we rename it, and let <code>dotProduct</code> call it:</p> <pre><code>generalized :: [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] generalized [] _ = [] generalized ((x,y):xys) z = (x*z,y):generalized (xys) z dotProduct :: [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] dotProduct xs z = generalized xs z </code></pre> <p>First, we parameterize it by the operation, specializing to multiplication for <code>dotProduct</code>:</p> <pre><code>generalized :: (Float -&gt; Float -&gt; Float) -&gt; [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] generalized _ [] _ = [] generalized f ((x,y):xys) z = (f x z,y):generalized f (xys) z dotProduct :: [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] dotProduct xs z = generalized (*) xs z </code></pre> <p>Next, we can observe two things: <code>generalized</code> doesn't depend on arithmetic directly anymore, so it can work on any type; and the only time <code>z</code> is used is as the second argument to <code>f</code>, so we can combine them into a single function argument:</p> <pre><code>generalized :: (a -&gt; b) -&gt; [(a, c)] -&gt; [(b, c)] generalized _ [] = [] generalized f ((x,y):xys) = (f x, y):generalized f (xys) dotProduct :: [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] dotProduct xs z = generalized (* z) xs </code></pre> <p>Now, we note that <code>f</code> is only used on the first element of a tuple. This sounds useful, so we'll extract that as a separate function: </p> <pre><code>generalized :: (a -&gt; b) -&gt; [(a, c)] -&gt; [(b, c)] generalized _ [] = [] generalized f (xy:xys) = onFirst f xy:generalized f (xys) onFirst :: (a -&gt; b) -&gt; (a, c) -&gt; (b, c) onFirst f (x, y) = (f x, y) dotProduct :: [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] dotProduct xs z = generalized (* z) xs </code></pre> <p>Now we again observe that, in <code>generalized</code>, <code>f</code> is only used with <code>onFirst</code>, so we again combine them into a single function argument:</p> <pre><code>generalized :: ((a, c) -&gt; (b, c)) -&gt; [(a, c)] -&gt; [(b, c)] generalized _ [] = [] generalized f (xy:xys) = f xy:generalized f (xys) dotProduct :: [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] dotProduct xs z = generalized (onFirst (* z)) xs </code></pre> <p>And once again, we observe that <code>generalized</code> no longer depends on the list containing tuples, so we let it work on any type:</p> <pre><code>generalized :: (a -&gt; b) -&gt; [a] -&gt; [b] generalized _ [] = [] generalized f (x:xs) = f x : generalized f xs </code></pre> <p>Now, compare the code for <code>generalized</code> to this:</p> <pre><code>map :: (a -&gt; b) -&gt; [a] -&gt; [b] map _ [] = [] map f (x:xs) = f x : map f xs </code></pre> <p>It also turns out that a slightly more general version of <code>onFirst</code> also exists, so we'll replace both that and <code>generalized</code> with their standard library equivalents:</p> <pre><code>import Control.Arrow (first) dotProduct :: [(Float, Integer)] -&gt; Float -&gt; [(Float, Integer)] dotProduct xs z = map (first (* z)) xs </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload