diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,23 @@
 # Revision history for zeolite-lang
 
+## 0.18.1.0  -- 2021-10-19
+
+### Language
+
+* **[fix]** Fixes issue with explicit return discards skipping generation of
+  function calls. Previously, `_ <- foo()` skipped generating the call to `foo`.
+
+### Libraries
+
+* **[new]** Adds `RandomExponential`, `RandomGaussian`, and `RandomUniform` to
+  `lib/math` for generating random `Float` values.
+
+* **[new]** Adds `Realtime.sleepSecondsPrecise` function to allow sleeps that
+  are more precise than the kernel's latency.
+
+* **[new]** Adds `checkGreaterThan` and `checkLessThan` to `Testing` in
+  `lib/testing`.
+
 ## 0.18.0.0  -- 2021-08-01
 
 ### Compiler CLI
diff --git a/lib/math/.zeolite-module b/lib/math/.zeolite-module
--- a/lib/math/.zeolite-module
+++ b/lib/math/.zeolite-module
@@ -10,5 +10,17 @@
     source: "lib/math/src/Extension_Math.cpp"
     categories: [Math]
   }
+  category_source {
+    source: "lib/math/src/Extension_RandomExponential.cpp"
+    categories: [RandomExponential]
+  }
+  category_source {
+    source: "lib/math/src/Extension_RandomGaussian.cpp"
+    categories: [RandomGaussian]
+  }
+  category_source {
+    source: "lib/math/src/Extension_RandomUniform.cpp"
+    categories: [RandomUniform]
+  }
 ]
 mode: incremental {}
diff --git a/lib/math/random.0rp b/lib/math/random.0rp
new file mode 100644
--- /dev/null
+++ b/lib/math/random.0rp
@@ -0,0 +1,46 @@
+/* -----------------------------------------------------------------------------
+Copyright 2021 Kevin P. Barry
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+----------------------------------------------------------------------------- */
+
+// Author: Kevin P. Barry [ta0kira@gmail.com]
+
+// Generates values of type #x.
+@value interface Generator<|#x> {
+  generate () -> (#x)
+}
+
+// Generates exponentially-distributed Float values.
+concrete RandomExponential {
+  refines Generator<Float>
+
+  // Creates a new generator with the specified lambda value.
+  @type new (Float) -> (Generator<Float>)
+}
+
+// Generates Gaussian-distributed Float values.
+concrete RandomGaussian {
+  refines Generator<Float>
+
+  // Creates a new generator with the specified mean and standard deviation.
+  @type new (Float,Float) -> (Generator<Float>)
+}
+
+// Generates uniformly-distributed Float values.
+concrete RandomUniform {
+  refines Generator<Float>
+
+  // Creates a new generator with the specified min and max values.
+  @type new (Float,Float) -> (Generator<Float>)
+}
diff --git a/lib/math/random.0rt b/lib/math/random.0rt
new file mode 100644
--- /dev/null
+++ b/lib/math/random.0rt
@@ -0,0 +1,125 @@
+/* -----------------------------------------------------------------------------
+Copyright 2021 Kevin P. Barry
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+----------------------------------------------------------------------------- */
+
+// Author: Kevin P. Barry [ta0kira@gmail.com]
+
+testcase "valid instantiations" {
+  success
+}
+
+unittest exponential {
+  Generator<Float> random <- RandomExponential.new(1.0)
+  Float value <- random.generate()
+}
+
+unittest gaussian {
+  Generator<Float> random <- RandomGaussian.new(0.0,1.0)
+  Float value <- random.generate()
+}
+
+unittest uniform {
+  Generator<Float> random <- RandomUniform.new(0.0,1.0)
+  Float value <- random.generate()
+}
+
+
+testcase "negative lambda in exponential" {
+  crash
+  require "lambda"
+  require "-1"
+}
+
+unittest test {
+  Generator<Float> random <- RandomExponential.new(-1.0)
+}
+
+
+testcase "negative standard deviation in gaussian" {
+  crash
+  require "standard deviation"
+  require "-1"
+}
+
+unittest test {
+  Generator<Float> random <- RandomGaussian.new(0.0,-1.0)
+}
+
+
+testcase "empty range in uniform" {
+  crash
+  require "range"
+  require "0,-1"
+}
+
+unittest test {
+  Generator<Float> random <- RandomUniform.new(0.0,-1.0)
+}
+
+
+testcase "distribution sanity checks" {
+  success
+}
+
+unittest exponential {
+  Int count <- 10000
+  Float lambda <- 10.0
+  $ReadOnly[count,lambda]$
+
+  Generator<Float> random <- RandomExponential.new(lambda)
+
+  Float sum <- 0.0
+  traverse (Counter.zeroIndexed(count) -> _) {
+    Float value <- random.generate()
+    \ Testing.checkGreaterThan<?>(value,0.0)
+    sum <- sum+value
+  }
+
+  \ Testing.checkBetween<?>(sum/count.asFloat(),0.9/lambda,1.1/lambda)
+}
+
+unittest gaussian {
+  Int count <- 10000
+  Float mean <- 100.0
+  Float sd <- 1.0
+  $ReadOnly[count,mean,sd]$
+
+  Generator<Float> random <- RandomGaussian.new(mean,sd)
+
+  Float sum <- 0.0
+  traverse (Counter.zeroIndexed(count) -> _) {
+    sum <- sum+random.generate()
+  }
+
+  \ Testing.checkBetween<?>(sum/count.asFloat(),mean-0.1*sd,mean+0.1*sd)
+}
+
+unittest uniform {
+  Int count <- 10000
+  Float min <- -11.0
+  Float max <- 5.0
+  $ReadOnly[count,min,max]$
+
+  Generator<Float> random <- RandomUniform.new(min,max)
+
+  Float sum <- 0.0
+  traverse (Counter.zeroIndexed(count) -> _) {
+    Float value <- random.generate()
+    \ Testing.checkBetween<?>(value,min,max)
+    sum <- sum+value
+  }
+
+  \ Testing.checkBetween<?>(sum/count.asFloat(),min-0.1*(max-min),max-0.1*(max-min))
+}
diff --git a/lib/math/src/Extension_RandomExponential.cpp b/lib/math/src/Extension_RandomExponential.cpp
new file mode 100644
--- /dev/null
+++ b/lib/math/src/Extension_RandomExponential.cpp
@@ -0,0 +1,81 @@
+/* -----------------------------------------------------------------------------
+Copyright 2021 Kevin P. Barry
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+----------------------------------------------------------------------------- */
+
+// Author: Kevin P. Barry [ta0kira@gmail.com]
+
+#include <random>
+
+#include "category-source.hpp"
+#include "Streamlined_RandomExponential.hpp"
+#include "Category_Float.hpp"
+#include "Category_Generator.hpp"
+#include "Category_RandomExponential.hpp"
+#include "Category_RandomUniform.hpp"
+
+#ifdef ZEOLITE_PUBLIC_NAMESPACE
+namespace ZEOLITE_PUBLIC_NAMESPACE {
+#endif  // ZEOLITE_PUBLIC_NAMESPACE
+
+BoxedValue CreateValue_RandomExponential(S<Type_RandomExponential> parent, const ValueTuple& args);
+
+struct ExtCategory_RandomExponential : public Category_RandomExponential {
+};
+
+struct ExtType_RandomExponential : public Type_RandomExponential {
+  inline ExtType_RandomExponential(Category_RandomExponential& p, Params<0>::Type params) : Type_RandomExponential(p, params) {}
+
+  ReturnTuple Call_new(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {
+    TRACE_FUNCTION("RandomExponential.new")
+    const PrimFloat Var_arg1 = (args.At(0)).AsFloat();
+    if (Var_arg1 <= 0) {
+      FAIL() << "Invalid lambda " << Var_arg1;
+    }
+    return ReturnTuple(CreateValue_RandomExponential(shared_from_this(), args));
+  }
+};
+
+struct ExtValue_RandomExponential : public Value_RandomExponential {
+  inline ExtValue_RandomExponential(S<Type_RandomExponential> p, const ValueTuple& args)
+    : Value_RandomExponential(p),
+      distribution_(args.At(0).AsFloat()) {}
+
+  ReturnTuple Call_generate(const BoxedValue& Var_self, const ParamTuple& params, const ValueTuple& args) final {
+    TRACE_FUNCTION("RandomExponential.generate")
+    return ReturnTuple(Box_Float(distribution_(generator_)));
+  }
+
+  std::default_random_engine generator_;
+  std::exponential_distribution<double> distribution_;
+};
+
+Category_RandomExponential& CreateCategory_RandomExponential() {
+  static auto& category = *new ExtCategory_RandomExponential();
+  return category;
+}
+
+S<Type_RandomExponential> CreateType_RandomExponential(Params<0>::Type params) {
+  static const auto cached = S_get(new ExtType_RandomExponential(CreateCategory_RandomExponential(), Params<0>::Type()));
+  return cached;
+}
+
+BoxedValue CreateValue_RandomExponential(S<Type_RandomExponential> parent, const ValueTuple& args) {
+  return BoxedValue(new ExtValue_RandomExponential(parent, args));
+}
+
+#ifdef ZEOLITE_PUBLIC_NAMESPACE
+}  // namespace ZEOLITE_PUBLIC_NAMESPACE
+using namespace ZEOLITE_PUBLIC_NAMESPACE;
+#endif  // ZEOLITE_PUBLIC_NAMESPACE
diff --git a/lib/math/src/Extension_RandomGaussian.cpp b/lib/math/src/Extension_RandomGaussian.cpp
new file mode 100644
--- /dev/null
+++ b/lib/math/src/Extension_RandomGaussian.cpp
@@ -0,0 +1,82 @@
+/* -----------------------------------------------------------------------------
+Copyright 2021 Kevin P. Barry
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+----------------------------------------------------------------------------- */
+
+// Author: Kevin P. Barry [ta0kira@gmail.com]
+
+#include <random>
+
+#include "category-source.hpp"
+#include "Streamlined_RandomGaussian.hpp"
+#include "Category_Float.hpp"
+#include "Category_Generator.hpp"
+#include "Category_RandomGaussian.hpp"
+#include "Category_RandomUniform.hpp"
+
+#ifdef ZEOLITE_PUBLIC_NAMESPACE
+namespace ZEOLITE_PUBLIC_NAMESPACE {
+#endif  // ZEOLITE_PUBLIC_NAMESPACE
+
+BoxedValue CreateValue_RandomGaussian(S<Type_RandomGaussian> parent, const ValueTuple& args);
+
+struct ExtCategory_RandomGaussian : public Category_RandomGaussian {
+};
+
+struct ExtType_RandomGaussian : public Type_RandomGaussian {
+  inline ExtType_RandomGaussian(Category_RandomGaussian& p, Params<0>::Type params) : Type_RandomGaussian(p, params) {}
+
+  ReturnTuple Call_new(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {
+    TRACE_FUNCTION("RandomGaussian.new")
+    const PrimFloat Var_arg1 = (args.At(0)).AsFloat();
+    const PrimFloat Var_arg2 = (args.At(1)).AsFloat();
+    if (Var_arg2 <= 0) {
+      FAIL() << "Invalid standard deviation " << Var_arg2;
+    }
+    return ReturnTuple(CreateValue_RandomGaussian(shared_from_this(), args));
+  }
+};
+
+struct ExtValue_RandomGaussian : public Value_RandomGaussian {
+  inline ExtValue_RandomGaussian(S<Type_RandomGaussian> p, const ValueTuple& args)
+    : Value_RandomGaussian(p),
+      distribution_(args.At(0).AsFloat(), args.At(1).AsFloat()) {}
+
+  ReturnTuple Call_generate(const BoxedValue& Var_self, const ParamTuple& params, const ValueTuple& args) final {
+    TRACE_FUNCTION("RandomGaussian.generate")
+    return ReturnTuple(Box_Float(distribution_(generator_)));
+  }
+
+  std::default_random_engine generator_;
+  std::normal_distribution<double> distribution_;
+};
+
+Category_RandomGaussian& CreateCategory_RandomGaussian() {
+  static auto& category = *new ExtCategory_RandomGaussian();
+  return category;
+}
+
+S<Type_RandomGaussian> CreateType_RandomGaussian(Params<0>::Type params) {
+  static const auto cached = S_get(new ExtType_RandomGaussian(CreateCategory_RandomGaussian(), Params<0>::Type()));
+  return cached;
+}
+
+BoxedValue CreateValue_RandomGaussian(S<Type_RandomGaussian> parent, const ValueTuple& args) {
+  return BoxedValue(new ExtValue_RandomGaussian(parent, args));
+}
+
+#ifdef ZEOLITE_PUBLIC_NAMESPACE
+}  // namespace ZEOLITE_PUBLIC_NAMESPACE
+using namespace ZEOLITE_PUBLIC_NAMESPACE;
+#endif  // ZEOLITE_PUBLIC_NAMESPACE
diff --git a/lib/math/src/Extension_RandomUniform.cpp b/lib/math/src/Extension_RandomUniform.cpp
new file mode 100644
--- /dev/null
+++ b/lib/math/src/Extension_RandomUniform.cpp
@@ -0,0 +1,81 @@
+/* -----------------------------------------------------------------------------
+Copyright 2021 Kevin P. Barry
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+----------------------------------------------------------------------------- */
+
+// Author: Kevin P. Barry [ta0kira@gmail.com]
+
+#include <random>
+
+#include "category-source.hpp"
+#include "Streamlined_RandomUniform.hpp"
+#include "Category_Float.hpp"
+#include "Category_Generator.hpp"
+#include "Category_RandomUniform.hpp"
+
+#ifdef ZEOLITE_PUBLIC_NAMESPACE
+namespace ZEOLITE_PUBLIC_NAMESPACE {
+#endif  // ZEOLITE_PUBLIC_NAMESPACE
+
+BoxedValue CreateValue_RandomUniform(S<Type_RandomUniform> parent, const ValueTuple& args);
+
+struct ExtCategory_RandomUniform : public Category_RandomUniform {
+};
+
+struct ExtType_RandomUniform : public Type_RandomUniform {
+  inline ExtType_RandomUniform(Category_RandomUniform& p, Params<0>::Type params) : Type_RandomUniform(p, params) {}
+
+  ReturnTuple Call_new(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {
+    TRACE_FUNCTION("RandomUniform.new")
+    const PrimFloat Var_arg1 = (args.At(0)).AsFloat();
+    const PrimFloat Var_arg2 = (args.At(1)).AsFloat();
+    if (Var_arg2 <= Var_arg1) {
+      FAIL() << "Invalid range (" << Var_arg1 << "," << Var_arg2 << ")";
+    }
+    return ReturnTuple(CreateValue_RandomUniform(shared_from_this(), args));
+  }
+};
+
+struct ExtValue_RandomUniform : public Value_RandomUniform {
+  inline ExtValue_RandomUniform(S<Type_RandomUniform> p, const ValueTuple& args)
+    : Value_RandomUniform(p),
+      distribution_(args.At(0).AsFloat(), args.At(1).AsFloat()) {}
+
+  ReturnTuple Call_generate(const BoxedValue& Var_self, const ParamTuple& params, const ValueTuple& args) final {
+    TRACE_FUNCTION("RandomUniform.generate")
+    return ReturnTuple(Box_Float(distribution_(generator_)));
+  }
+
+  std::default_random_engine generator_;
+  std::uniform_real_distribution<double> distribution_;
+};
+
+Category_RandomUniform& CreateCategory_RandomUniform() {
+  static auto& category = *new ExtCategory_RandomUniform();
+  return category;
+}
+
+S<Type_RandomUniform> CreateType_RandomUniform(Params<0>::Type params) {
+  static const auto cached = S_get(new ExtType_RandomUniform(CreateCategory_RandomUniform(), Params<0>::Type()));
+  return cached;
+}
+
+BoxedValue CreateValue_RandomUniform(S<Type_RandomUniform> parent, const ValueTuple& args) {
+  return BoxedValue(new ExtValue_RandomUniform(parent, args));
+}
+
+#ifdef ZEOLITE_PUBLIC_NAMESPACE
+}  // namespace ZEOLITE_PUBLIC_NAMESPACE
+using namespace ZEOLITE_PUBLIC_NAMESPACE;
+#endif  // ZEOLITE_PUBLIC_NAMESPACE
diff --git a/lib/testing/helpers.0rp b/lib/testing/helpers.0rp
--- a/lib/testing/helpers.0rp
+++ b/lib/testing/helpers.0rp
@@ -68,4 +68,38 @@
     #x defines Equals<#x>
     #x defines LessThan<#x>
   (#x,#x,#x) -> ()
+
+  // Check that the value is above the limit. Crashes if it is not in the range.
+  //
+  // Args:
+  // - #x: Actual value.
+  // - #x: Lower bound.
+  //
+  // Notes:
+  // - This could be done without Equals, except that some types have
+  //   "undefined" values (e.g., NaN, for Float) that prevent inferring equality
+  //   from less-than comparisons.
+  // - This comparison doesn't allow the value to equal the bound.
+  @type checkGreaterThan<#x>
+    #x requires Formatted
+    #x defines Equals<#x>
+    #x defines LessThan<#x>
+  (#x,#x) -> ()
+
+  // Check that the value is below the limit. Crashes if it is not in the range.
+  //
+  // Args:
+  // - #x: Actual value.
+  // - #x: Upper bound.
+  //
+  // Notes:
+  // - This could be done without Equals, except that some types have
+  //   "undefined" values (e.g., NaN, for Float) that prevent inferring equality
+  //   from less-than comparisons.
+  // - This comparison doesn't allow the value to equal the bound.
+  @type checkLessThan<#x>
+    #x requires Formatted
+    #x defines Equals<#x>
+    #x defines LessThan<#x>
+  (#x,#x) -> ()
 }
diff --git a/lib/testing/helpers.0rx b/lib/testing/helpers.0rx
--- a/lib/testing/helpers.0rx
+++ b/lib/testing/helpers.0rx
@@ -76,6 +76,26 @@
     }
   }
 
+  checkGreaterThan (x,l) {
+    if (lessEquals<?>(x,l)) {
+      fail(String.builder()
+          .append(x.formatted())
+          .append(" is not greater than ")
+          .append(l.formatted())
+          .build())
+    }
+  }
+
+  checkLessThan (x,h) {
+    if (lessEquals<?>(h,x)) {
+      fail(String.builder()
+          .append(x.formatted())
+          .append(" is not less than ")
+          .append(h.formatted())
+          .build())
+    }
+  }
+
   @type lessEquals<#x>
     #x defines Equals<#x>
     #x defines LessThan<#x>
diff --git a/lib/testing/tests.0rt b/lib/testing/tests.0rt
--- a/lib/testing/tests.0rt
+++ b/lib/testing/tests.0rt
@@ -138,3 +138,43 @@
 unittest test {
   \ Testing.checkBetween<?>(14,15,13)
 }
+
+
+testcase "checkGreaterThan success" {
+  success
+}
+
+unittest test {
+  \ Testing.checkGreaterThan<?>(13,11)
+}
+
+
+testcase "checkGreaterThan fail" {
+  crash
+  require stderr "13"
+  require stderr "14"
+}
+
+unittest test {
+  \ Testing.checkGreaterThan<?>(13,14)
+}
+
+
+testcase "checkLessThan success" {
+  success
+}
+
+unittest test {
+  \ Testing.checkLessThan<?>(13,14)
+}
+
+
+testcase "checkLessThan fail" {
+  crash
+  require stderr "13"
+  require stderr "11"
+}
+
+unittest test {
+  \ Testing.checkLessThan<?>(13,11)
+}
diff --git a/lib/thread/src/Extension_Realtime.cpp b/lib/thread/src/Extension_Realtime.cpp
--- a/lib/thread/src/Extension_Realtime.cpp
+++ b/lib/thread/src/Extension_Realtime.cpp
@@ -23,12 +23,17 @@
 
 #include <chrono>
 #include <iomanip>
+#include <thread>
 
 #include "category-source.hpp"
 #include "Streamlined_Realtime.hpp"
 #include "Category_Float.hpp"
 #include "Category_Realtime.hpp"
 
+#ifndef SLEEP_SPINLOCK_LIMIT
+#define SLEEP_SPINLOCK_LIMIT 0.001
+#endif
+
 #ifdef ZEOLITE_PUBLIC_NAMESPACE
 namespace ZEOLITE_PUBLIC_NAMESPACE {
 #endif  // ZEOLITE_PUBLIC_NAMESPACE
@@ -42,18 +47,34 @@
   ReturnTuple Call_sleepSeconds(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {
     TRACE_FUNCTION("Realtime.sleepSeconds")
     const PrimFloat Var_arg1 = (args.At(0)).AsFloat();
-    if (Var_arg1 < 0) {
-      FAIL() << "Bad wait time " << Var_arg1;
+    if (Var_arg1 > 0) {
+      std::this_thread::sleep_for(std::chrono::duration<double>(Var_arg1));
     }
-    struct timespec timeout{ (int) trunc(Var_arg1), (int) (1000000000.0 * (Var_arg1-trunc(Var_arg1))) };
-    struct timespec remainder;
-    while (nanosleep(&timeout, &remainder) != 0) {
-      if (errno == EINTR) {
-        timeout = remainder;
+    return ReturnTuple();
+  }
+
+  ReturnTuple Call_sleepSecondsPrecise(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {
+    TRACE_FUNCTION("Realtime.sleepSecondsPrecise")
+    const PrimFloat Var_arg1 = (args.At(0)).AsFloat();
+
+    const auto spinlock_limit = std::chrono::duration<double>(SLEEP_SPINLOCK_LIMIT);
+
+    const auto target_time =
+      std::chrono::high_resolution_clock::now().time_since_epoch() +
+      std::chrono::duration<double>(Var_arg1);
+
+    while (true) {
+      const auto now = std::chrono::high_resolution_clock::now().time_since_epoch();
+      if (now >= target_time) break;
+      const auto sleep_time = target_time - now;
+      if (sleep_time <= spinlock_limit) {
+        while (std::chrono::high_resolution_clock::now().time_since_epoch() < target_time);
+        break;
       } else {
-        FAIL() << "Error sleeping: " << strerror(errno) << " (error " << errno << ")";
+        std::this_thread::sleep_for(sleep_time - spinlock_limit);
       }
     }
+
     return ReturnTuple();
   }
 
diff --git a/lib/thread/time.0rp b/lib/thread/time.0rp
--- a/lib/thread/time.0rp
+++ b/lib/thread/time.0rp
@@ -21,6 +21,9 @@
   // Sleep for the given number of seconds.
   @type sleepSeconds (Float) -> ()
 
+  // Sleep for the given number of seconds, with more precision.
+  @type sleepSecondsPrecise (Float) -> ()
+
   // Get a timestamp from a monotonic clock.
   //
   // Notes:
diff --git a/lib/thread/time.0rt b/lib/thread/time.0rt
--- a/lib/thread/time.0rt
+++ b/lib/thread/time.0rt
@@ -16,22 +16,24 @@
 
 // Author: Kevin P. Barry [ta0kira@gmail.com]
 
-testcase "negative sleepSeconds() crashes" {
-  crash
-  require "-0\.1"
+testcase "zero sleep is allowed" {
+  success
 }
 
-unittest test {
-  \ Realtime.sleepSeconds(-0.1)
+unittest zeroSleep {
+  \ Realtime.sleepSeconds(0.0)
 }
 
+unittest negativeSleep {
+  \ Realtime.sleepSeconds(-0.1)
+}
 
-testcase "zero sleepSeconds() is allowed" {
-  success
+unittest zeroPrecise {
+  \ Realtime.sleepSecondsPrecise(0.0)
 }
 
-unittest test {
-  \ Realtime.sleepSeconds(0.0)
+unittest negativePrecise {
+  \ Realtime.sleepSecondsPrecise(-0.1)
 }
 
 
@@ -46,14 +48,32 @@
 }
 
 
+testcase "sleepSecondsPrecise() does not interfere with test timeout" {
+  crash
+  require "signal 14"
+  timeout 1
+}
+
+unittest test {
+  \ Realtime.sleepSecondsPrecise(5.0)
+}
+
+
 testcase "monoSeconds() diff is somewhat accurate" {
   success
   timeout 2
 }
 
-unittest test {
+unittest testSleep {
   Float start <- Realtime.monoSeconds()
   \ Realtime.sleepSeconds(0.5)
   Float stop <- Realtime.monoSeconds()
-  \ Testing.checkBetween<?>(stop-start,0.5,0.75)
+  \ Testing.checkBetween<?>(stop-start,0.5,0.6)
+}
+
+unittest testPrecise {
+  Float start <- Realtime.monoSeconds()
+  \ Realtime.sleepSecondsPrecise(0.5)
+  Float stop <- Realtime.monoSeconds()
+  \ Testing.checkBetween<?>(stop-start,0.5,0.51)
 }
diff --git a/src/CompilerCxx/CxxFiles.hs b/src/CompilerCxx/CxxFiles.hs
--- a/src/CompilerCxx/CxxFiles.hs
+++ b/src/CompilerCxx/CxxFiles.hs
@@ -725,7 +725,7 @@
 createFunctionDispatch :: CategoryName -> SymbolScope -> [ScopedFunction c] -> CompiledData [String]
 createFunctionDispatch n s fs = function where
   function
-    | null filtered = onlyCode $ "{ " ++ fallback ++ " }"
+    | null filtered = onlyCode fallback
     | otherwise = onlyCodes $ [typedef] ++ concat (map table $ byCategory) ++ metaTable ++ select
   filtered = filter ((== s) . sfScope) fs
   flatten f = f:(concat $ map flatten $ sfMerges f)
diff --git a/src/CompilerCxx/Procedure.hs b/src/CompilerCxx/Procedure.hs
--- a/src/CompilerCxx/Procedure.hs
+++ b/src/CompilerCxx/Procedure.hs
@@ -279,7 +279,7 @@
   _ <- processPairsT alwaysPair (fmap assignableName as) ts
   _ <- processPairsT (createVariable r fa) as ts
   maybeSetTrace c
-  variableTypes <- sequence $ map (uncurry getVariableType) $ zip (pValues as) (pValues ts)
+  variableTypes <- sequence $ map getVariableType (pValues as)
   assignAll (zip3 ([0..] :: [Int]) variableTypes (pValues as)) e'
   where
     message = "In assignment at " ++ formatFullContext c
@@ -288,11 +288,11 @@
       csWrite ["{","const auto r = " ++ useAsReturns e2 ++ ";"]
       sequence_ $ map assignMulti vs
       csWrite ["}"]
-    getVariableType (CreateVariable _ t _) _ = return t
-    getVariableType (ExistingVariable (InputValue c2 n)) _ = do
+    getVariableType (CreateVariable _ t _) = return t
+    getVariableType (ExistingVariable (InputValue c2 n)) = do
       (VariableValue _ _ t _) <- csGetVariable (UsedVariable c2 n)
       return t
-    getVariableType (ExistingVariable (DiscardInput _)) t = return t
+    getVariableType _ = return undefined
     createVariable r fa (CreateVariable c2 t1 n) t2 =
       "In creation of " ++ show n ++ " at " ++ formatFullContext c2 ??> do
         self <- autoSelfType
@@ -315,7 +315,8 @@
       (VariableValue _ s _ _) <- csGetVariable (UsedVariable c2 n)
       scoped <- autoScope s
       csWrite [scoped ++ variableName n ++ " = " ++ writeStoredVariable t e2 ++ ";"]
-    assignSingle _ _ = return ()
+    assignSingle (_,_,ExistingVariable (DiscardInput _)) e2 = do
+      csWrite ["(void)" ++ useAsWhatever e2 ++ ";"]
     assignMulti (i,t,CreateVariable _ _ n) =
       csWrite [variableName n ++ " = " ++
                writeStoredVariable t (UnwrappedSingle $ "r.At(" ++ show i ++ ")") ++ ";"]
diff --git a/src/Parser/Procedure.hs b/src/Parser/Procedure.hs
--- a/src/Parser/Procedure.hs
+++ b/src/Parser/Procedure.hs
@@ -104,7 +104,7 @@
       return $ InputValue [c] v
     discard = do
       c <- getSourceContext
-      sepAfter (string_ "_")
+      sepAfter_ kwIgnore
       return $ DiscardInput [c]
 
 instance ParseFromSource (OutputValue SourceContext) where
diff --git a/src/Types/Procedure.hs b/src/Types/Procedure.hs
--- a/src/Types/Procedure.hs
+++ b/src/Types/Procedure.hs
@@ -51,6 +51,7 @@
   getOperatorContext,
   getOperatorName,
   getStatementContext,
+  isAssignableDiscard,
   isDiscardedInput,
   isFunctionOperator,
   isNoTrace,
@@ -203,6 +204,10 @@
 assignableName (CreateVariable _ _ n)              = n
 assignableName (ExistingVariable (InputValue _ n)) = n
 assignableName _                                   = discardInputName
+
+isAssignableDiscard :: Assignable c -> Bool
+isAssignableDiscard (CreateVariable _ _ _) = False
+isAssignableDiscard (ExistingVariable v)   = isDiscardedInput v
 
 data VoidExpression c =
   Conditional (IfElifElse c) |
diff --git a/tests/leak-check/README.md b/tests/leak-check/README.md
--- a/tests/leak-check/README.md
+++ b/tests/leak-check/README.md
@@ -58,8 +58,12 @@
 
 ```shell
 # The "race" argument is important.
-valgrind --leak-check=yes $ZEOLITE_PATH/tests/leak-check/LeakTest race
+$ZEOLITE_PATH/tests/leak-check/LeakTest race
 ```
+
+*Do not use `valgrind` to run in `race` mode!* The latency introduced by
+tracking memory usage will eliminate the race conditions that this mode is
+intended to introduce, defeating the purpose of the test.
 
 You should see `no race conditions this time` upon success. Any sort of error
 message means a crash, and thus a test failure.
diff --git a/tests/regressions.0rt b/tests/regressions.0rt
--- a/tests/regressions.0rt
+++ b/tests/regressions.0rt
@@ -292,3 +292,24 @@
     return "return"
   }
 }
+
+
+testcase "Issue #185 is fixed" {
+  // https://github.com/ta0kira/zeolite/issues/185
+  crash
+  require "message"
+}
+
+concrete Type {
+  @type sideEffects () -> (Bool)
+}
+
+define Type {
+  sideEffects () {
+    fail("message")
+  }
+}
+
+unittest test {
+  _ <- Type.sideEffects()
+}
diff --git a/zeolite-lang.cabal b/zeolite-lang.cabal
--- a/zeolite-lang.cabal
+++ b/zeolite-lang.cabal
@@ -1,7 +1,7 @@
 cabal-version:       2.2
 
 name:                zeolite-lang
-version:             0.18.0.1
+version:             0.18.1.0
 synopsis:            Zeolite is a statically-typed, general-purpose programming language.
 
 description:
