content: -- powers :: Gen [Int]
  on powers(n)
      script f
          on |λ|(x)
              x ^ n as integer
          end |λ|
      end script
      fmapGen(f, enumFrom(0))
  end powers
  
  
  -- TEST ---------------------------------------------------
  on run
      take(10, ¬
          drop(20, ¬
              differenceGen(powers(2), powers(3))))
  
      --> {529, 576, 625, 676, 784, 841, 900, 961, 1024, 1089}
  end run
  
  
  -- GENERIC ------------------------------------------------
  
  -- Just :: a -> Maybe a
  on Just(x)
      {type:"Maybe", Nothing:false, Just:x}
  end Just
  
  -- Nothing :: Maybe a
  on Nothing()
      {type:"Maybe", Nothing:true}
  end Nothing
  
  -- Tuple (,) :: a -> b -> (a, b)
  on Tuple(a, b)
      {type:"Tuple", |1|:a, |2|:b, length:2}
  end Tuple
  
  
  -- differenceGen :: Gen [a] -> Gen [a] -> Gen [a]
  on differenceGen(ga, gb)
      -- All values of ga except any
      -- already seen in gb.
      script
          property g : zipGen(ga, gb)
          property bs : {}
          property xy : missing value
          on |λ|()
              set xy to g's |λ|()
              if missing value is xy then
                  xy
              else
                  set x to |1| of xy
                  set y to |2| of xy
                  set bs to {y} & bs
                  if bs contains x then
                      |λ|() -- Next in series.
                  else
                      x
                  end if
              end if
          end |λ|
      end script
  end differenceGen
  
  
  -- drop :: Int -> [a] -> [a]
  -- drop :: Int -> String -> String
  on drop(n, xs)
      set c to class of xs
      if script is not c then
          if string is not c then
              if n < length of xs then
                  items (1 + n) thru -1 of xs
              else
                  {}
              end if
          else
              if n < length of xs then
                  text (1 + n) thru -1 of xs
              else
                  ""
              end if
          end if
      else
          take(n, xs) -- consumed
          return xs
      end if
  end drop
  
  
  -- enumFrom :: Int -> [Int]
  on enumFrom(x)
      script
          property v : missing value
          on |λ|()
              if missing value is not v then
                  set v to 1 + v
              else
                  set v to x
              end if
              return v
          end |λ|
      end script
  end enumFrom
  
  
  -- fmapGen <$> :: (a -> b) -> Gen [a] -> Gen [b]
  on fmapGen(f, gen)
      script
          property g : mReturn(f)
          on |λ|()
              set v to gen's |λ|()
              if v is missing value then
                  v
              else
                  g's |λ|(v)
              end if
          end |λ|
      end script
  end fmapGen
  
  
  -- length :: [a] -> Int
  on |length|(xs)
      set c to class of xs
      if list is c or string is c then
          length of xs
      else
          (2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)
      end if
  end |length|
  
  
  -- Lift 2nd class handler function into 1st class script wrapper
  -- mReturn :: First-class m => (a -> b) -> m (a -> b)
  on mReturn(f)
      if script is class of f then
          f
      else
          script
              property |λ| : f
          end script
      end if
  end mReturn
  
  
  -- take :: Int -> [a] -> [a]
  -- take :: Int -> String -> String
  on take(n, xs)
      set c to class of xs
      if list is c then
          if 0 < n then
              items 1 thru min(n, length of xs) of xs
          else
              {}
          end if
      else if string is c then
          if 0 < n then
              text 1 thru min(n, length of xs) of xs
          else
              ""
          end if
      else if script is c then
          set ys to {}
          repeat with i from 1 to n
              set v to xs's |λ|()
              if missing value is v then
                  return ys
              else
                  set end of ys to v
              end if
          end repeat
          return ys
      else
          missing value
      end if
  end take
  
  
  -- uncons :: [a] -> Maybe (a, [a])
  on uncons(xs)
      set lng to |length|(xs)
      if 0 = lng then
          Nothing()
      else
          if (2 ^ 29 - 1) as integer > lng then
              if class of xs is string then
                  set cs to text items of xs
                  Just(Tuple(item 1 of cs, rest of cs))
              else
                  Just(Tuple(item 1 of xs, rest of xs))
              end if
          else
              set nxt to take(1, xs)
              if {} is nxt then
                  Nothing()
              else
                  Just(Tuple(item 1 of nxt, xs))
              end if
          end if
      end if
  end uncons
  
  
  -- zipGen :: Gen [a] -> Gen [b] -> Gen [(a, b)]
  on zipGen(ga, gb)
      script
          property ma : missing value
          property mb : missing value
          on |λ|()
              if missing value is ma then
                  set ma to uncons(ga)
                  set mb to uncons(gb)
              end if
              if Nothing of ma or Nothing of mb then
                  missing value
              else
                  set ta to Just of ma
                  set tb to Just of mb
                  set x to Tuple(|1| of ta, |1| of tb)
                  set ma to uncons(|2| of ta)
                  set mb to uncons(|2| of tb)
                  return x
              end if
          end |λ|
      end script
  end zipGen
  