translate :: VirtualSegmentAlgebra a
          => NodeMap VSL.TVSL
          -> AlgNode
          -> VecBuild a (VSLDVec a) (VSLRVec a) (Res (VSLDVec a) (VSLRVec a))
translate vlNodes n = do
    r <- fromDict n

    case r of
        -- The VSL node has already been encountered and translated.
        Just res -> return $ res

        -- The VSL node has not been translated yet.
        Nothing  -> do
            let vlOp = getVSL n vlNodes
            r' <- case VSL.unVSL vlOp of
                TerOp t c1 c2 c3 -> do
                    c1' <- translate vlNodes c1
                    c2' <- translate vlNodes c2
                    c3' <- translate vlNodes c3
                    lift $ translateTerOp t c1' c2' c3'
                BinOp b c1 c2    -> do
                    c1' <- translate vlNodes c1
                    c2' <- translate vlNodes c2
                    lift $ translateBinOp b c1' c2'
                UnOp u c1        -> do
                    c1' <- translate vlNodes c1
                    lift $ translateUnOp u c1'
                NullaryOp o      -> lift $ translateNullary o

            insertTranslation n r'
            return r'
translate :: VirtualSegmentAlgebra a
          => NodeMap VSL.TVSL
          -> AlgNode
          -> VecBuild a (VSLDVec a) (VSLRVec a) (Res (VSLDVec a) (VSLRVec a))
translate vlNodes n = do
    r <- fromDict n

    case r of
        -- The VSL node has already been encountered and translated.
        Just res -> return $ res

        -- The VSL node has not been translated yet.
        Nothing  -> do
            let vlOp = getVSL n vlNodes
            r' <- case VSL.unVSL vlOp of
                TerOp t c1 c2 c3 -> do
                    c1' <- translate vlNodes c1
                    c2' <- translate vlNodes c2
                    c3' <- translate vlNodes c3
                    lift $ translateTerOp t c1' c2' c3'
                BinOp b c1 c2    -> do
                    c1' <- translate vlNodes c1
                    c2' <- translate vlNodes c2
                    lift $ translateBinOp b c1' c2'
                UnOp u c1        -> do
                    c1' <- translate vlNodes c1
                    lift $ translateUnOp u c1'
                NullaryOp o      -> lift $ translateNullary o

            insertTranslation n r'
            return r'
translate vlNodes n = do
    r <- fromDict n

    case r of
        -- The VSL node has already been encountered and translated.
        Just res -> return $ res

        -- The VSL node has not been translated yet.
        Nothing  -> do
            let vlOp = getVSL n vlNodes
            r' <- case VSL.unVSL vlOp of
                TerOp t c1 c2 c3 -> do
                    c1' <- translate vlNodes c1
                    c2' <- translate vlNodes c2
                    c3' <- translate vlNodes c3
                    lift $ translateTerOp t c1' c2' c3'
                BinOp b c1 c2    -> do
                    c1' <- translate vlNodes c1
                    c2' <- translate vlNodes c2
                    lift $ translateBinOp b c1' c2'
                UnOp u c1        -> do
                    c1' <- translate vlNodes c1
                    lift $ translateUnOp u c1'
                NullaryOp o      -> lift $ translateNullary o

            insertTranslation n r'
            return r'