December 20, 2017

Haskell and type composition the easy way

Below is a small Haskell module that I wrote as an exercise. It defines nifty little utility in the form of a generic type composition mechanism. A composite type is any type in which a type constructor is applied to a another type (denoted with type variables, like a (b c)). It can represent for example a list of optional values, i.e [Maybe Int], aka [] (Maybe Int), or an IO operation sequence that operates on a list of values (IO [a]), etc.

Haskell provides many useful high-level programming constructs for managing individual types, but its standard libraries lack a truly flexible denotation for extending those high-level functions to composition data types. Some of these issues are solved by using so-called "monad transformers", which are very sophisticated, but must be separately defined for each individual monad. And as the name says, their application is limited to monads, and they cannot be used for the many quite useful classes of type constructors at the lower levels of the functor hierarchy, such as Functors, Foldables, Traversables or Applicatives.

The small (and silly) test function at the end of the modules shows, how this modules enables flexible intermingling of overlapping data types using both the monadic do syntax and plain fmap calls. While this only seems to apply to compositions of two types at a time, it quite easily generalizes to any number of types, via meta-composition. If a, b, c ... g are functors, then so is (Comp a b). IO [Maybe Int] can be tagged as Comp (Comp IO []) Maybe Int. Hmmm... Maybe the next step is to generalize these operations to a recursive data type representing arbitrary chains of composition.

One cannot help but appreciate how all of these very useful operations are relatively short one-liners. (Readability for persons not familiar with Haskell or Scala is another question.

{-# LANGUAGE FlexibleContexts #-}

-- A generic type composition module by Reino Ruusu, December 2017, Espoo, Finland

-- The simple type composition tag defined here can do many of the tasks that
-- monad transformers are used for, but in a much more generic way, allowing
-- useful compositions of Functors, Foldables, Traversables, Applicatives and
-- Monads (with certain restrictions).

import Control.Applicative
import Control.Monad
import Data.Foldable
import Data.List

-- This type tags a composition type as a parameterized type constructor
newtype Comp m n a = Comp (m (n a))

-- Decorate a `raw' composition type
comp :: m (n a) -> Comp m n a
comp = Comp

-- Undecorate a tagged composition type
decomp :: Comp m n a -> m (n a)
decomp (Comp x) = x

-- Lift a raw outer type to the composition type (inner has to be Applicative)
lift1 :: (Functor m, Applicative n) => m a -> Comp m n a
lift1 = Comp . (pure <$>)

-- Lift a raw inner type to the composition type (outer has to be Applicative)
lift2 :: (Applicative m) => n a -> Comp m n a
lift2 = Comp . pure

-- Foldable instance
instance (Foldable m, Foldable n) => Foldable (Comp m n) where
  -- foldMap :: Monoid k => (a -> k) -> Comp m n a -> k
  foldMap f (Comp x) = foldr (\a l -> foldMap f a `mappend` l) mempty x 

-- Functor instance
instance (Functor m, Functor n) => Functor (Comp m n) where
  -- fmap :: (a -> b) -> (Comp m n a) -> (Comp m n b)
  fmap f (Comp x) = Comp (fmap (fmap f) x)

-- Applicative instance
instance (Applicative m, Applicative n) => Applicative (Comp m n) where
  -- pure :: a -> Comp m n a
  pure = comp . pure . pure
  -- (<*>) :: Comp m n (a -> b) -> Comp m n a -> Comp m n b
  Comp f <*> Comp x = Comp (liftA2 (<*>) f x)

-- Monoid instance
instance (Applicative m, Applicative n, Monoid a) => Monoid (Comp m n a) where
  -- mempty :: Comp m n a
  mempty = pure mempty
  -- mappend :: Comp m n a -> Comp m n a -> Comp m n a
  mappend = (*>)

-- Monad instance (only works if inner type is Traversable, unlike IO, for example)
instance (Monad m, Monad n, Traversable n) => Monad (Comp m n) where
  -- return = pure
  -- (>>=) :: Comp m n a -> (a -> Comp m n b) -> Comp m n b
  Comp x >>= f = Comp $ x >>= fmap join . sequence . fmap (decomp . f)

-- Test routine, builds a (Comp IO []) monad in the do block
-- First fmap (show) applies to (Comp IO [] Int), resulting in (Comp IO [] String).
-- After decomp, second fmap applies to (IO [String]).
-- Execution results in 4*(1 + 4) calls to print, and a return value of
-- "4, 5, 6, 7, 3, 4, 5, 6, 2, 3, 4, 5, 1, 2, 3, 4"

test :: () -> IO String
test () = fmap (intercalate ", ") $ decomp $ fmap (show) $ do
  a <- lift2 [1, 2, 3, 4]
  lift1 (print a)
  b <- lift2 [5, 6, 7, 8]
  lift1 (print (a, b))
  return (b - a) :: Comp IO [] Int

November 26, 2017

The beauty of Haskell

I've been taking a more serious look into Haskell programming, and have deeply fell in love with its "purity", i.e. its nature as a purely functional programming language, in which everything is expressed entirely in terms of what happens to data.

Another very attracting feature is its very rich toolbox of higher level programming constructs that allow one to express complex data processing tasks in just a few function calls.

A third beautiful aspect of the language is its typing system, which provides automated type matching of undeclared functions and variables. It provides a type checking system just like any other strongly typed language, but without the need to separately declare the types of each and every variable.

On the other hand, these features make Haskell quite difficult to read for people who are not familiar with it, but on the other hand, the amount of code to read can be very small, and absolutely oozing with semantics, i.e. there code is typically very dense, and the reader is not bothered with unnecessary details, such as the name of an iteration variable.

The way in which stateful programming is expressed in Haskell, which is a pure language in the sense that absolutely no side effects are allowed in the code, can be a bit confusing for a beginner, but after one gets the hang of it, one starts to really appreciate the pure functional programming paradigm.

With no side effects and a strong typing system, any program that compiles actually does something, there is no concept of a run-time failure, except in the case of a match against a partially defined pattern, or similar situations.

Additionally, lazy evaluation allows one to express interactive processes simply as ordinary pure functions, which is really convenient, though may be quite confusing.

Below is an example of a hangman program, written in Haskell, using lazy evaluation and the State monad. The program lets the user guess a word one letter at a time. If the user makes 5 wrong guesses, he loses the game.

-- A hangman game using the State monad in Haskell by Reino Ruusu, 2017

import System.Environment
import System.Random
import Control.Monad.State.Lazy
import Data.Char

-- Hangman IO
main = do
  args <- getArgs
  if null args then
    putStrLn "Please provide a file containing words. (One per line.)"
  else do
    -- Select random word
    words <- readFile (head args)
    word <- randomElement (lines words)
    -- Play the game
    interact $ hangmanMain (map toLower word)

-- Hangman game as a pure lazy string processing function
hangmanMain :: String -> String -> String
hangmanMain word = unlines . ("Welcome to Haskell Hangman":) . hangman . ("":) . lines
    hangman input = map snd $ takeUntil fst $ evalState (sequence steps) initialState
        steps = map (hangmanIteration word) input
        initialState = (initialGuess, 0)
            -- Alphabetic characters replaced with underscores
            initialGuess = map (\w -> if isAlpha w then '_' else w) word

-- A single iteration of hangman: State update followed by output
hangmanIteration :: String -> String -> State (String, Int) (Bool, String)
hangmanIteration word input = update >> report
    update = unless (null input) $ do
      -- Check user's guess and update state
      (guess, strikes) <- get
      if elem l word && not (elem l guess) then
        put (newguess guess, strikes) -- Hit
        put (guess, strikes + 1) -- Miss
        l = head input
        newguess = zipWith (\w g -> if w == l then w else g) word
    report = do
      (guess, strikes) <- get
      -- Status message - example: __a_e__ ###
      let status = guess ++ " " ++ (replicate strikes '#')
      -- Check game outcome
      return $ if guess == word then
                 (True, status ++ "\nYou won!") -- Win
               else if strikes >= 5 then
                 (True, status ++ "\nYou lost! (" ++ word ++ ")") -- Loss
                 (False, status) -- Continue

-- Utility functions

-- Take elements up to and including the first for which f returs True
takeUntil f l = first ++ [head last]
  where (first, last) = break f l

-- Select a random element from a list (as an IO operation)
randomElement list = do
  i <- randomRIO (0, length list - 1)
  return (list !! i)

The execution of the game looks like this:
Welcome to Haskell Hangman
____________ #
____________ ##
_i________i_ ##
_i__o_____i_ ##
_i__ou____i_ ##
_is_ou__s_i_ ##
_iscou__s_i_ ##
viscou__s_i_ ##
viscou_ts_i_ ##
viscou_ts_i_ ###
viscounts_i_ ###
viscounts_ip ###
viscounts_ip ####
viscountship ####
You won!
Note how the game itself is defined as a pure function that simply processes the input string into the output string. Furthermore, all iteration in the code happens via higher level programming constructs that clearly define rules for processing of data, instead of bothering with low-level things such as updating an iteration variable. All the IO is performed by calling this function via the interact function, which simply maps input and output from the console to a pure function from string to string. The business logic can then be defined purely by describing the relationship between the input and the output, without bothering with any aspects of the IO operations.

The steps of the game are here described using the State monad, which allows one to define processing as a combination of stateful operations.

An almost equally elegant solution can be achieved by the very versatile mapAccumL operation, which provides for simultaneous accumulation of state and processing of data. However, in this approach, the hangmanIteration function is much less understandable in isolation, whereas in the version based on the State monad, the state update is directly specified by the definition of the iteration function itself. The state monad allows us to also make use of elegant and semantically rich higher level constructs, such as unless above.

-- A hangman game in Haskell by Reino Ruusu, 2017

import System.Environment
import System.Random
import Data.List
import Data.Char

-- Hangman IO
main = do
  args <- getArgs
  if null args then
    putStrLn "Please provide a file containing words. (One per line.)"
  else do
    -- Select random word
    words <- readFile (head args)
    word <- randomElement (lines words)
    -- Play the game
    interact $ hangmanMain (map toLower word)

-- Hangman game as a pure lazy string processing function
hangmanMain :: String -> String -> String
hangmanMain word = unlines . ("Welcome to Haskell Hangman":) . hangman . ("":) . lines
    hangman input = map snd $ takeUntil fst output
        output = snd $ mapAccumL (hangmanIteration word) initialState input
        initialState = (initialGuess, 0)
            -- Alphabetic characters replaced with underscores
            initialGuess = map (\w -> if isAlpha w then '_' else w) word

-- A single iteration of hangman: State update followed by output
hangmanIteration :: String -> (String, Int) -> String -> ((String, Int), (Bool, String))
hangmanIteration word state input = (newState, report newState)
    -- Check user's guess and update state
    newState = if null input then
               else if elem l word && not (elem l guess) then
                 (newguess guess, strikes) -- Hit
                 (guess, strikes + 1) -- Miss
        l = head input
        (guess, strikes) = state
        newguess = zipWith (\w g -> if w == l then w else g) word
    report (guess, strikes) = let
      -- Status message - example: __a_e__ ###
      status = guess ++ " " ++ (replicate strikes '#')
      -- Check game outcome
      in if guess == word then
           (True, status ++ "\nYou won!") -- Win
         else if strikes >= 5 then
           (True, status ++ "\nYou lost! (" ++ word ++ ")") -- Loss
           (False, status) -- Continue

-- Utility functions

-- Take elements up to and including the first for which f returs True
takeUntil f l = first ++ [head last]
  where (first, last) = break f l

-- Select a random element from a list (as an IO operation)
randomElement list = do
  i <- randomRIO (0, length list - 1)
  return (list !! i)

January 30, 2015

Building standalone Simulink models with calls to external libraries

Matlab ​Simulink can compile and build simulation models into stadalone executables that do not require the presense of any runtime binaries from Matlab. However there are a few limitations, that I have had to overcome this week:

  1. There can be no algebraic loops in the model.
  2. Certain Matlab functions are not available.

Eliminating algebraic loops in the model is sometimes possible by reformulating the problem. This is also a good idea in any case, as the convergence of the algebraic loop solver of Simulink is not in any way perfect, possibly resulting in a termination of the simulation.

Below is presented a way to overcome the second restriction in relation to functions that are used for calling external libraries.

Matlab provides a few functions for calling functions in a dynamically loaded library file. (.dll in Windows, .so in Linux):

  • loadlibrary(libname, hfile)
    Loads a DLL file into Matlab.
    • libname is the name of the library, wihtout the file name suffix (.dll/.so)
    • hfile is the name of a C-language header file that declares the functions provided by the DLL.
  • calllib(libname,funcname,arg1,...,argN)
    Calls a function provided by the DLL.
    • loadlibrary must be used before calling this function.
  • libpointer(datatype, value)
    Creates a pointer object that can be used for reading data that is written by a library function into a buffer provided as an argument.
These functions are very convenient, because they can automatically transform the Matlab data types into the correct forms expected by the library function. However, they are not available for use in a compiled Simulink model. When executed within Matlab, the Simulink model is always compiled into an S-function. To be able to access loadlibrary, callib and libpointer, they must be declared using coder.extrinsic(), which provides access to these functions.

However, when a Simulink model is compiled into a completely standalone executable, these functions are not available even with the coder.extrinsic() declaration. If the model contains a user-defined block, such as "MATLAB function", "Level-2 MATLAB S-Function" or "MATLAB System", which contains calls to library functions using the above-mentioned functions, building a standalone executable will fail with an error message: "The extrinsic function 'libpointer' is not available for standalone code generation. It must be eliminated for stand-alone code to be generated."

However, there is an alternative way of calling external library functions from compiled Matlab code:

  • coder.ceval('FCN',X1,...XN)
    This is a function that can only be used in MATLAB code that is compiled into C code. It is a kind of macro that simply places a call into the generated C code without making any checks on its arguments.
  • coder.cinclude(headerfile)
    Causes the addition of an #include statement in the generated C code.

Unfortunately the use of calllib and coder.ceval is mutually exclusive; calllib can only be used in non-compiled models and coder.ceval can only be used in compiled models. Fortunately this can be checked at "run-time" in the Matlab code, by checking the value of the variable When code is compiled into an S-function within Matlab, this variable has the value 'sfun'. When the code is compiled into a standalone model executable, this variable has the value 'standalone'. This can be checked in the Matlab code using ordinary if statements, so it is possible to write custom blocks that work both in Matlab and as standalone executables.

  use_coder = ~strcmp(, 'sfun');

  if use_coder
     coder.ceval('myfunction', arg1, arg2, arg3);
     calllib('library', 'myfunction', arg1, arg2, arg3);

Unfortunately it is not so easy as this. To be able to use coder.ceval(), the exectable must be linked against the DLL using a .lib file, forming a fixed dependency between the executable and the DLL(s). This unfortunately prevents calls to identically named functions in several different DLLs.

A bigger difference between coder.ceval() and calllib() is that coder.ceval() makes absolutely not checks or conversions for the datatypes of the arguments. All arguments must already be of a suitable data type, and any variables that are to be passed using a pointer (or reference in C++) must be explicitly declared using coder.ref(). Otherwise the result will most probably be a hard crash of the standalone model.

Lets take as an example the following C language delaration for a function that returns the average of an array of floats and writes the standard deviation into a pointer value.

  double stats(float *buf, double *sd_out, int bufsize);

While completely okay when used with callib(), the following call has a number of problems.

  n = 10;
  values = rand(1, n);
  sd = 0.0;

  // This will crash!!
  mean = coder.ceval('stats', values, sd, n);

The vector 'values' would be passed into the function as double pointer instead of float, as required. 'sd' is passed by value, not as a pointer. 'n' would be passed as a double instead of an int.
Finally, without a prior declaration of 'mean', Matlab Coder has no way to infer the data type of the return value, resulting in an error during build.

Below is a corrected version of the call:

  n = int32(10);
  values = single(rand(1, n));
  sd = 0.0;
  mean = 0.0;
  mean = coder.ceval('stats', coder.rref(values), coder.ref(sd), n);

To catch more potential typing errors, a call to coder.cinclude('libraryheader.h') should be located at some point, so that a declaration for the library function is added to the compiled C code.

It is quite natural for libraries to require calls to some kind of initialization functions, and a very natural place to locate these would be in an initialization function for the block that uses the library. Unfortunately, when building a standalone executable, these calls will be made before the Simulink Coder starts to build the executable, and the initialization calls will be completely omitted from the standalone model, resulting in possibly mysterious errors.

A possible solution is to move any such calls from the initialization functions into a conditional clause at the dependent code, which is only executed at the first call. An easy way to achieve it is to use a local persistent variable like this:

  function y = fcn(xin, par1, par2)
    persistent initialized;
    if isempty(initialized)
      initialized = true;
      coder.ceval('myinitializationcall', par1, par2);

To gain access to necessary parameter values for the relocated initialization call, some additional parameters may need to be added to the code block. Below is an example of how to do this using the Model Explorer.

Let's say that we have a Matlab function block like this:

The block has a mask that defines a single integer input (Parameter1) that is used as an argument in an initialization call to a custom library:

The function itself is also implemented as a simple call to the same library:

  function y = fcn(u)
    y = callib('mylibrary', 'myfun', u);

The coder.extrisic() call is necessary here, because the function is compiled into a MEX function by Simulink, even when the model is simulated in Matlab. The initialization call on the other hand is made by the Matlab interpreter, in which calllib() is always available.

Now if we want to be able to use the block in a standalone Simulink model executable, we need to replace the initialization calls in the mask with calls that are made in the function itself. For this purpose, we can add an additional argument for the function, which provides the value of the mask parameter. For this, we need to open the Model Explorer and select the MATLAB Function block (Right-click/Explore will do). With the "Add Data" command, we can insert the necessary parameter into the function. Note, that the scope of the added data item must be set to "Parameter", instead of the default scope of "Input".

Then we can add the equivalent call to coder.ceval() into the function and also add a conditional code block for the initialization call, like this:

  function y = fcn(u, Parameter1)
    persistent init_called;

    if strcmp(, 'sfun')
      y = callib('mylibrary', 'myfun', u);
      if isempty(init_called)
        init_called = true;
        param = int32(Parameter1);
        coder.ceval('myinit', param);
      % make sure of the right types
      y = 0.0;
      tmp = double(u);
      y = coder.ceval('myfun', tmp);

To be able to build the model, we also need to add 'mylibrary.lib' as an external library in the code generation configuration for the whole model (Code Generation/Custom Code/Libraries). After doing this, we are ready to build the model as blazingly fast and completely standalone executable with no additional runtime library dependencies.

July 13, 2012

Drone Warfare, Blowback and PTSD

In The Real Blowback Fallacy at, John Poindexter has good counterarguments to Christopher Swift in
It means that if five members of his group agreed that drone strikes aid in recruiting AQAP members, then roughly 3,000,000 other Yemenis must also support that conclusion.
He is spot on contrasting the local actions of AQAP with those of the US.
It certainly shouldn’t be the role of the U.S. to police Yemen, but if the money is going to be spent, I would rather see it go to feeding some poor family or digging wells in the desert than burning the flesh off infants or dismembering whole families at random.
Despite all the talk about precision strikes, the fact is that since Vietnam, force protection has been allowed to completely dominate over the need to avoid collateral damage. Even "precision" use of air force will always cause much more collateral damage than would be caused by ground forces.

As it happens, drone warfare can be even more damaging to psyche of the operator than participation in ordinary warfare. Going to work to kill people during the day, perhaps just kilometers away from one's home, and returning home every evening to spend time with the family, makes the killing a normal part of everyday life, causing a far deeper impact on one's conscience than acts that are made in the special circumstances of ordinary warfare. P.W. Singer explains it well in this video.

This problem has been well recognized by the people involved, but the solution proposed by David Axe a few weeks ago is definitely not the right solution.
A more independent drone could alert its controller for assistance only when it has spotted a likely target. The operator would give a thumbs-up or thumbs-down for the robot to fire a weapon. With only minimal involvement, the human being could avoid feeling fully responsible for the consequences of the strike. Drones are already becoming more autonomous by the day, opening the door for a different emotional dynamic between them and their operators.
Besides being flagrantly immoral, this would just heavily increase the number of collateral casualties and cause even bigger blowback.

April 26, 2010

About My Master's Thesis

This post might well be the first that has any connection at all to my everyday life.

I haven't written anything here for a very long time. I have been busy enough with other things. On my spare time I have been finishing my long overdue master's thesis at the Helsinki University of Technology, which is nowadays a part of the Aalto University in Helsinki, Finland.

My thesis concerns digital texturing of solid objects, and in it I describe how texture mapping, as it is understood in computer graphics, can be used for designing objects with custom low-level surface details. The work is based on an old project in which we produced highly accurate laser-machined details into the surfaces of plastic injection molds, based on ordinary bump map images and 3D models of the mold cavities. The point of my thesis is that digital texture mapping is a viable tool for the design and manufacturing of (embossed) surface details, as long as the right tools are made available.

As one part of the work I developed a new method for adaptive displacement mapping of triangular meshes that is specifically aimed at well-specified tolerances at an optimal number of output primitives. It can be readily used to produce textured geometries for rapid prototyping or laser machining.

It's applicability is not necessarily limited to manufacturing, but could be used for visualization as well. At least it easily beats the adaptive displacement in 3dsMax.

Here is a flat shaded rendering of a sample model from the algorithm, along with the tileable displacement texture. (It's an old concept design, not any actual phone model.)

If anyone is interested in asking more, please feel free to email me at (firstname.lastname).

November 29, 2009

Speculation vs. Actual Investments - The Carrot and the Stick

Paul Krugman takes a stand in support of taxing financial transactions. He mentions activities in the financial sector that Adair Turner referred to as "socially useless", meaning especially speculation. I'm all any means of reducing excessive speculation, if a workable solution can be found.

On the other hand, there could be more talk about encouraging more socially useful activities. Investment must be directed away from speculative secondary markets and into primary markets that create new real assets.

There was a failed attempt at getting tax relief for "angel investors" in Finland. The idea was quite sensibly dropped, because an "angel investor" is not a concept that anybody is able to define in a watertight manner in a legal sense.

So I thought: Why not give a tax relief to all capital gains income from first resales of stock that was bought in an issue. Thus, the original holder of any newly issued equity would have a favorable treatment. This would both create an incentive for participating in stock issues and a disincentive for giving up the original ownership.

This would encourage people to invest in newly started or growing businesses. It would also encourage companies to acquire new capital, thus acting as a disincentive for excessive leverage.

As a bonus, there would be no need to define any ambiguous terms like "angel investor".

October 14, 2009

John Hussman - Zen and the Art of Market Analysis

Fund manager John Hussman makes some interesting, if a bit gimmicky, connections between the zen Buddhist teachings of Thich Nhat Hanh and financial decision making in his latest newsletter:
The best way of preparing for the future is to take good care of the present, because we know that if the present is made up of the past, then the future will be made up of the present. All we need to be responsible for is the present moment. Only the present is within our reach. To care for the present is to care for the future.

Thich Nhat Hanh

This week's comment is dedicated to my dear friend Thich Nhat Hanh, a Vietnamese Buddhist monk who was born on October 11, 1926, having been born previously in January of that same year, and twice again about 25 years earlier, not to mention countless other times through his ancestors, teachers, and other non-Thich Nhat Hanh elements. Thay (the Vietnamese word for “teacher”) would simplify this by saying that today is his eighty-third “continuation day,” because to say it is his birthday is not very accurate.


So here's another koan – “If a share of stock is sold in a forest, and nobody is around to buy it, does it still generate a fill?”

The immediate implication of interbeing is that we are forced to think about “general equilibrium” rather than imagining that one side of a trade can exist without the other. This immediately clarifies all sorts of misconceptions that we could fall victim to if we aren't careful.

For example, it immediately tells us that “cash on the sidelines” is not a useful concept, except as a measure of issuance. See, whatever “cash” is there on the sidelines exists because government has created paper money, or the Treasury has issued bills, or because companies have issued commercial paper. Until those securities are actually physically retired, they will and must remain “on the sidelines” because somebody will have to hold them.

If Mickey wants to sell his money market fund to buy stocks, the money market fund has to sell commercial paper to Nicky, whose cash goes to Mickey, who uses it to buy stocks from Ricky. In the end, the commercial paper Mickey used to have is now held by Nicky. The cash that Nicky used to have is now held by Ricky, and the stock that Ricky used to have is now held by Mickey. There is exactly the same amount of “cash on the sidelines” after this transaction as there was before it.


Here's another koan:

A novice monk approaches his teacher and asks “What is the price movement of one share being bought?”

The teacher holds out a cypress leaf in his palm and asks, “Did I catch the leaf as it fell from the tree, or did I raise it from the ground?”

We are used to thinking that the act of buying necessarily implies rising prices. But think about this for a second. In either case, the teacher gets the cypress leaf. What makes the difference so far as direction is concerned is where the pressure is coming from. If the cypress leaf is being offered down by gravity, it is caught on a decline. If the leaf is being lifted by the teacher, it is caught on an advance. Remember that. It is easy to get trapped in wrong thinking by people who talk about “cash on the sidelines” or talk about “investors” buying or selling in aggregate.

There was no excess of stock that was “sold” in March that has to be “bought” back now. Investors didn't “get out” of the market last year, and we shouldn't think that they have to “come into” the market now. Every share that was sold was bought. That has been true for every minute of every trading day since the beginning of the financial markets.
These insights, though perfectly understandable without esoteric zen Buddhist thinking, are spot on. There is no such thing as "cash on the sidelines".

Instead, one could try to evaluate the amount of potentially untapped credit. Reductions in credit lines all around have been taking this measure down lately. Both businesses and households have been shrinking their debt loads in the US somewhat. Unfortunately unemployment, lack of demand and shrinking collateral are eating the other side of the equation.

Thich Nhat Hanh writes well about zen in terms that are easily understandable by the average layperson. I liked his book "Peace is Every Step". He has lots of interesting advice for practicing zen in everyday situations, like driving a car or washing dishes. Unfortunately I have great problems in adhering to the principle of mindfulness. Absent-mindedness is my second nature. (Or is it the first?)