diff --git a/examples/array_ops.ion b/examples/array_ops.ion
new file mode 100644
index 0000000000000000000000000000000000000000..b7337e8eef1885562b086f3838de46c03c946255
--- /dev/null
+++ b/examples/array_ops.ion
@@ -0,0 +1,17 @@
+let array = [ 4 4 5 5 5 6 6 6 6 ]
+echo @array
+let array ++= [ 1 2 3 ]
+echo @array
+let array ::= [ 1 2 3 ]
+echo @array
+let array \\= [ 4 5 6 ]
+echo @array
+
+let array = [ 1 2 2 3 3 3 ]
+echo @array
+let array ++= 4
+echo @array
+let array ::= 0
+echo @array
+let array \\= 3
+echo @array
diff --git a/examples/array_ops.out b/examples/array_ops.out
new file mode 100644
index 0000000000000000000000000000000000000000..4304d5d07a939192afe9a8c14dad0ddec8dc2aeb
--- /dev/null
+++ b/examples/array_ops.out
@@ -0,0 +1,8 @@
+4 4 5 5 5 6 6 6 6
+4 4 5 5 5 6 6 6 6 1 2 3
+1 2 3 4 4 5 5 5 6 6 6 6 1 2 3
+1 2 3 1 2 3
+1 2 2 3 3 3
+1 2 2 3 3 3 4
+0 1 2 2 3 3 3 4
+0 1 2 2 4
diff --git a/src/lib/builtins/exists.rs b/src/lib/builtins/exists.rs
index 95a733ac619a445193eb47eefd14b38944e2ff15..e555196d5f97e7067c800dc321047139c0cf8025 100644
--- a/src/lib/builtins/exists.rs
+++ b/src/lib/builtins/exists.rs
@@ -150,7 +150,7 @@ fn function_is_defined(function: &str, shell: &Shell) -> bool {
 
 #[test]
 fn test_evaluate_arguments() {
-    use parser::assignments::{KeyBuf, Primitive};
+    use lexers::assignments::{KeyBuf, Primitive};
     let mut shell = shell::ShellBuilder::new().as_library();
 
     // assert_eq!(evaluate_arguments(&[], &mut sink, &shell), Ok(false));
@@ -404,7 +404,7 @@ fn test_string_var_is_not_empty() {
 
 #[test]
 fn test_function_is_defined() {
-    use parser::assignments::{KeyBuf, Primitive};
+    use lexers::assignments::{KeyBuf, Primitive};
     let mut shell = shell::ShellBuilder::new().as_library();
 
     // create a simple dummy function
diff --git a/src/lib/parser/assignments/actions.rs b/src/lib/parser/assignments/actions.rs
index 011b540319efd3dd6f7faa48ac0e3eda38796eab..795c6860f0fbd24f43da75c213826682e16c22a2 100644
--- a/src/lib/parser/assignments/actions.rs
+++ b/src/lib/parser/assignments/actions.rs
@@ -120,6 +120,7 @@ impl<'a> Action<'a> {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use lexers::assignments::*;
 
     fn split(input: &str) -> (String, Operator, String) {
         let (keys, op, vals) = assignment_lexer(input);
@@ -246,5 +247,47 @@ mod tests {
                 "[four five]",
             ))
         );
+        let (keys, op, values) = split("array ++= [one two three four five]");
+        let actions = AssignmentActions::new(&keys, op, &values).collect::<Vec<_>>();
+        assert_eq!(actions.len(), 1);
+        assert_eq!(
+            actions[0],
+            Ok(Action::UpdateArray(
+                Key {
+                    name: "array",
+                    kind: Primitive::Any,
+                },
+                Operator::Concatenate,
+                "[one two three four five]",
+            ))
+        );
+        let (keys, op, values) = split("array ::= [1 2 3 4 5]");
+        let actions = AssignmentActions::new(&keys, op, &values).collect::<Vec<_>>();
+        assert_eq!(actions.len(), 1);
+        assert_eq!(
+            actions[0],
+            Ok(Action::UpdateArray(
+                Key {
+                    name: "array",
+                    kind: Primitive::Any,
+                },
+                Operator::ConcatenateHead,
+                "[1 2 3 4 5]",
+            ))
+        );
+        let (keys, op, values) = split(r"array \\= [foo bar baz]");
+        let actions = AssignmentActions::new(&keys, op, &values).collect::<Vec<_>>();
+        assert_eq!(actions.len(), 1);
+        assert_eq!(
+            actions[0],
+            Ok(Action::UpdateArray(
+                Key {
+                    name: "array",
+                    kind: Primitive::Any,
+                },
+                Operator::Filter,
+                "[foo bar baz]",
+            ))
+        );
     }
 }
diff --git a/src/lib/parser/statement/functions.rs b/src/lib/parser/statement/functions.rs
index c12421b15c33f3632e5044a81e12353197340f3d..6d5cc8b142e7f89cf38a2a6c81f64263e54063c9 100644
--- a/src/lib/parser/statement/functions.rs
+++ b/src/lib/parser/statement/functions.rs
@@ -19,9 +19,8 @@ pub(crate) fn collect_arguments(args: KeyIterator) -> Result<Vec<KeyBuf>, TypeEr
 
 #[cfg(test)]
 mod tests {
-    use super::{
-        super::super::assignments::{KeyBuf, Primitive}, *,
-    };
+    use lexers::assignments::{KeyBuf, Primitive};
+    use parser::statement::functions::{collect_arguments, parse_function}; 
 
     #[test]
     fn function_parsing() {
diff --git a/src/lib/parser/statement/parse.rs b/src/lib/parser/statement/parse.rs
index bab71b16f3edb846164094a70e6412815ffc70c0..35750efc5cd619cadc9932414772aafa9fd2c052 100644
--- a/src/lib/parser/statement/parse.rs
+++ b/src/lib/parser/statement/parse.rs
@@ -223,7 +223,7 @@ pub(crate) fn parse(code: &str) -> Statement {
 mod tests {
     use self::pipelines::PipeItem;
     use super::*;
-    use parser::assignments::{KeyBuf, Primitive};
+    use lexers::assignments::{KeyBuf, Primitive};
     use shell::{flow_control::Statement, Job, JobKind};
 
     #[test]
diff --git a/src/lib/shell/assignments.rs b/src/lib/shell/assignments.rs
index 57cf9ac18dc75898b41f86d7732af25fec67fd15..599e52fe604c8e9b9f477301046ea1581483edac 100644
--- a/src/lib/shell/assignments.rs
+++ b/src/lib/shell/assignments.rs
@@ -148,36 +148,96 @@ impl VariableStore for Shell {
         };
         for action in actions_step1 {
             match action {
-                Ok(Action::UpdateArray(key, Operator::Equal, expression)) => {
-                    match value_check(self, &expression, &key.kind) {
-                        Ok(VariableType::Array(values)) => {
-                            // When we changed the HISTORY_IGNORE variable, update the
-                            // ignore patterns. This happens first because `set_array`
-                            // consumes 'values'
-                            if key.name == "HISTORY_IGNORE" {
-                                self.update_ignore_patterns(&values);
+                Ok(Action::UpdateArray(key, operator, expression)) => {
+                    match operator {
+                        Operator::Equal => match value_check(self, &expression, &key.kind) {
+                            Ok(VariableType::Array(values)) => {
+                                // When we changed the HISTORY_IGNORE variable, update the
+                                // ignore patterns. This happens first because `set_array`
+                                // consumes 'values'
+                                if key.name == "HISTORY_IGNORE" {
+                                    self.update_ignore_patterns(&values);
+                                }
+                                collected.insert(key.name, VariableType::Array(values));
+                            }
+                            Ok(VariableType::Str(value)) => {
+                                collected.insert(key.name, VariableType::Str(value));
+                            }
+                            Ok(VariableType::HashMap(map)) => {
+                                collected.insert(key.name, VariableType::HashMap(map));
+                            }
+                            Err(why) => {
+                                eprintln!("ion: assignment error: {}: {}", key.name, why);
+                                return FAILURE;
                             }
-                            collected.insert(key.name, VariableType::Array(values));
+                            _ => (),
                         }
-                        Ok(VariableType::Str(value)) => {
-                            collected.insert(key.name, VariableType::Str(value));
+                        Operator::Concatenate => match value_check(self, &expression, &key.kind) {
+                            Ok(VariableType::Array(values)) => {
+                                match self.variables.get_mut(key.name) {
+                                    Some(VariableType::Array(ref mut array)) => {
+                                        array.extend(values);
+                                    }
+                                    None => {
+                                        eprintln!("ion: assignment error: {}: cannot concatenate non-array variable", key.name);
+                                        return FAILURE;
+                                    }
+                                    _ => (),
+                                }
+                            }
+                            Err(why) => {
+                                eprintln!("ion: assignment error: {}: {}", key.name, why);
+                                return FAILURE;
+                            }
+                            _ => (),
                         }
-                        Ok(VariableType::HashMap(map)) => {
-                            collected.insert(key.name, VariableType::HashMap(map));
+                        Operator::ConcatenateHead => match value_check(self, &expression, &key.kind) {
+                            Ok(VariableType::Array(values)) => {
+                                match self.variables.get_mut(key.name) {
+                                    Some(VariableType::Array(ref mut array)) => {
+                                        for (index, value) in values.into_iter().enumerate() {
+                                            array.insert(index, value);
+                                        }
+                                    }
+                                    None => {
+                                        eprintln!("ion: assignment error: {}: cannot head concatenate non-array variable", key.name);
+                                        return FAILURE;
+                                    }
+                                    _ => (),
+                                }
+                            }
+                            Err(why) => {
+                                eprintln!("ion: assignment error: {}: {}", key.name, why);
+                                return FAILURE;
+                            }
+                            _ => (),
                         }
-                        Err(why) => {
-                            eprintln!("ion: assignment error: {}: {}", key.name, why);
-                            return FAILURE;
+                        Operator::Filter => match value_check(self, &expression, &key.kind) {
+                            Ok(VariableType::Array(values)) => {
+                                match self.variables.get_mut(key.name) {
+                                    Some(VariableType::Array(ref mut array)) => {
+                                        let mut iterator: Box<Iterator<Item=&String>> = Box::new(array.iter());
+                                        for value in &values {
+                                            iterator = Box::new(iterator.filter(move |item| *item != value));
+                                        }
+                                        *array = iterator.cloned().collect();
+                                    }
+                                    None => {
+                                        eprintln!("ion: assignment error: {}: cannot head concatenate non-array variable", key.name);
+                                        return FAILURE;
+                                    }
+                                    _ => (),
+                                }
+                            }
+                            Err(why) => {
+                                eprintln!("ion: assignment error: {}: {}", key.name, why);
+                                return FAILURE;
+                            }
+                            _ => (),
                         }
                         _ => (),
                     }
                 }
-                Ok(Action::UpdateArray(..)) => {
-                    eprintln!(
-                        "ion: arithmetic operators on array expressions aren't supported yet."
-                    );
-                    return FAILURE;
-                }
                 Ok(Action::UpdateString(key, operator, expression)) => {
                     if ["HOME", "HOST", "PWD", "MWD", "SWD", "?"].contains(&key.name) {
                         eprintln!("ion: not allowed to set {}", key.name);
@@ -186,11 +246,53 @@ impl VariableStore for Shell {
 
                     match value_check(self, &expression, &key.kind) {
                         Ok(VariableType::Str(value)) => {
-                            if operator == Operator::Equal {
-                                collected.insert(key.name, VariableType::Str(value));
-                                continue;
+                            match operator {
+                                Operator::Equal => {
+                                    collected.insert(key.name, VariableType::Str(value));
+                                    continue;
+                                }
+                                Operator::Concatenate => {
+                                    match self.variables.get_mut(key.name) {
+                                        Some(VariableType::Array(ref mut array)) => {
+                                            array.push(value);
+                                        }
+                                        None => {
+                                            eprintln!("ion: assignment error: {}: cannot concatenate non-array variable", key.name);
+                                            return FAILURE;
+                                        }
+                                        _ => (),
+                                    }
+                                    continue;
+                                }
+                                Operator::ConcatenateHead => {
+                                    match self.variables.get_mut(key.name) {
+                                        Some(VariableType::Array(ref mut array)) => {
+                                            array.insert(0, value);
+                                        }
+                                        None => {
+                                            eprintln!("ion: assignment error: {}: cannot head concatenate non-array variable", key.name);
+                                            return FAILURE;
+                                        }
+                                        _ => (),
+                                    }
+                                    continue;
+                                }
+                                Operator::Filter => {
+                                    match self.variables.get_mut(key.name) {
+                                        Some(VariableType::Array(ref mut array)) => {
+                                            *array = array.iter().filter(move |item| **item != value).cloned().collect();
+                                        }
+                                        None => {
+                                            eprintln!("ion: assignment error: {}: cannot head concatenate non-array variable", key.name);
+                                            return FAILURE;
+                                        }
+                                        _ => (),
+                                    }
+                                    continue;
+                                }
+                                _ => (),
                             }
-                            match self.variables.lookup_any(key.name) {
+                            match self.variables.get_ref(key.name) {
                                 Some(VariableType::Str(lhs)) => {
                                     let result = math(&lhs, &key.kind, operator, &value, |value| {
                                         collected.insert(key.name, VariableType::Str(unsafe {
@@ -289,7 +391,7 @@ impl VariableStore for Shell {
                             if let Primitive::Indexed(ref index_value, ref index_kind) = key.kind {
                                 match value_check(self, index_value, index_kind) {
                                     Ok(VariableType::Str(ref index)) => {
-                                        match self.variables.lookup_any_mut(key.name) {
+                                        match self.variables.get_mut(key.name) {
                                             Some(VariableType::HashMap(map)) => {
                                                 map.entry(SmallString::from_str(index)).or_insert(VariableType::Str(value));
                                             }
diff --git a/src/lib/shell/variables/mod.rs b/src/lib/shell/variables/mod.rs
index c4332c7c05b936e5b31748b639c2955181b4897f..c93f2b6fa77eff8a88c1894e4b9e5db833bcf0b6 100644
--- a/src/lib/shell/variables/mod.rs
+++ b/src/lib/shell/variables/mod.rs
@@ -232,27 +232,33 @@ impl Variables {
             self.scopes[self.current].namespace = namespace;
         }
     }
+
     pub fn pop_scope(&mut self) {
         self.scopes[self.current].clear();
         self.current -= 1;
     }
+
     pub fn pop_scopes<'a>(&'a mut self, index: usize) -> impl Iterator<Item = Scope> + 'a {
         self.current = index;
         self.scopes.drain(index+1..)
     }
+
     pub fn append_scopes(&mut self, scopes: Vec<Scope>) {
         self.scopes.drain(self.current+1..);
         self.current += scopes.len();
         self.scopes.extend(scopes);
     }
+
     pub fn scopes(&self) -> impl Iterator<Item = &Scope> {
         let amount = self.scopes.len() - self.current - 1;
         self.scopes.iter().rev().skip(amount)
     }
+
     pub fn scopes_mut(&mut self) -> impl Iterator<Item = &mut Scope> {
         let amount = self.scopes.len() - self.current - 1;
         self.scopes.iter_mut().rev().skip(amount)
     }
+
     pub fn index_scope_for_var(&self, name: &str) -> Option<usize> {
         let amount = self.scopes.len() - self.current - 1;
         for (i, scope) in self.scopes.iter().enumerate().rev().skip(amount) {
@@ -262,10 +268,12 @@ impl Variables {
         }
         None
     }
+
     pub fn shadow(&mut self, name: SmallString, value: VariableType) -> Option<VariableType> {
         self.scopes[self.current].insert(name, value)
     }
-    pub fn lookup_any(&self, mut name: &str) -> Option<&VariableType> {
+
+    pub fn get_ref(&self, mut name: &str) -> Option<&VariableType> {
         let mut up_namespace: isize = 0;
         if name.starts_with("global::") {
             name = &name["global::".len()..];
@@ -291,7 +299,8 @@ impl Variables {
         }
         None
     }
-    pub fn lookup_any_mut(&mut self, name: &str) -> Option<&mut VariableType> {
+
+    pub fn get_mut(&mut self, name: &str) -> Option<&mut VariableType> {
         if name.starts_with("super::") || name.starts_with("global::") {
             // Cannot mutate outer namespace
             return None;
@@ -450,7 +459,7 @@ impl Variables {
                 Some(("env", variable)) => env::var(variable).map(Into::into).ok().map(|s| T::from(VariableType::Str(s))),
                 Some(("super", _)) | Some(("global", _)) | None => {
                     // Otherwise, it's just a simple variable name.
-                    match self.lookup_any(name) {
+                    match self.get_ref(name) {
                         Some(VariableType::Str(val)) => Some(T::from(VariableType::Str(val.clone()))),
                         _ => env::var(name).ok().map(|s| T::from(VariableType::Str(s))),
                     }
@@ -488,22 +497,22 @@ impl Variables {
                 }
             }
         } else if specified_type == TypeId::of::<types::Alias>() {
-            match self.lookup_any(name) {
+            match self.get_ref(name) {
                 Some(VariableType::Alias(alias)) => Some(T::from(VariableType::Alias((*alias).clone()))),
                 _ => None
             }
         } else if specified_type == TypeId::of::<types::Array>() {
-            match self.lookup_any(name) {
+            match self.get_ref(name) {
                 Some(VariableType::Array(array)) => Some(T::from(VariableType::Array(array.clone()))),
                 _ => None
             }
         } else if specified_type == TypeId::of::<types::HashMap>() {
-            match self.lookup_any(name) {
+            match self.get_ref(name) {
                 Some(VariableType::HashMap(hash_map)) => Some(T::from(VariableType::HashMap(hash_map.clone()))),
                 _ => None
             }
         } else if specified_type == TypeId::of::<Function>() {
-            match self.lookup_any(name) {
+            match self.get_ref(name) {
                 Some(VariableType::Function(func)) => Some(T::from(VariableType::Function(func.clone()))),
                 _ => None
             }
@@ -514,7 +523,7 @@ impl Variables {
 
     pub fn set<T: Into<VariableType>>(&mut self, name: &str, var: T) {
         let var = var.into();
-        match self.lookup_any_mut(&name) {
+        match self.get_mut(&name) {
             Some(VariableType::Str(ref mut str_)) => {
                 if !name.is_empty() {
                     if let VariableType::Str(var_str) = var {