-2

I understand conceptually what all of these are, I'm just hoping for some code examples of how to implement them in ML and Haskell.

  • 3
    What do you mean by "implement"? Do you want code samples that are themselves with static scope, dynamic scope, or lazy evaluation, or do you want to implement an interpreter in ml or Haskell that has these features? In either case, the question is a bit broad. – Alec Nov 27 '16 at 18:37
  • http://okmij.org/ftp/Computation/dynamic-binding.html – coredump Nov 27 '16 at 18:47
  • @Alec the first option – Mike Harris Nov 27 '16 at 18:53

1 Answers1

1

Haskell variables (top level definitions, variables in patterns, etc.) are all statically scoped. For example, the program:

y = "global value"
f = print y
g = let y = "local value" in f

main = g

will print "global value". Even though, in the definition of g, the function f is used after "redefining" y, this redefinition doesn't affect the definition of f which uses the statically (AKA lexically) scoped definition of y in force where f was defined.

If you want to "implement" dynamic scope, you have to be more specific about what you really mean. If you're wondering if you can write a function in plain Haskell, like:

addY :: Int -> Int
addY x = x + y

such that y might refer to a different variable from one call to the next, then the answer is no. In this definition, y always refers to the same variable (which, in Haskell, means the same, immutable value) which can be determined by static analysis of the program and cannot be dynamically redefined.

[[Edit: As @Jon Purdy points out, though, there's a Haskell extension that supports a form of dynamic scope such that the following prints various dynamically scoped local values with the same function.

{-# LANGUAGE ImplicitParams #-}
f :: (?y :: String) => IO ()
f = print ?y
g = let ?y = "g's local value" in f
h = let ?y = "h's local value" in f
main = do
  g                -- prints g's local value
  h                -- prints h's local value
  let ?y = "main's local value" in f  -- prints main's value

--end of edit--]]

For lazy evaluation, there are many examples, such as the following entered into an interactive GHCi session:

take 3 [1,2..]    -- gives [1,2,3]

let x = (15^2, 6 `div` 0)
fst x             -- gives 225
let y = snd x
y                 -- *** Exception: divide by zero

In the first line, if the evaluation was strict, the attempt to fully evaluate the infinite list [1,2..] (can also be written [1..] -- just counts up 1,2,3,.. forever) would go into an infinite loop, and the take function would never be called. In the second example, if evaluation was strict, the division by zero error would occur when x was defined, not only after we tried to print its second component.

K. A. Buhr
  • 45,621
  • 3
  • 45
  • 71
  • There is an extension for dynamically scoped variables: `ImplicitParams`. For example, if you have `pr :: (?currentOutputHandle :: Handle, Show a) => a -> IO (); pr x = hPrint ?currentOutputHandle x`, then you can locally redirect the output with e.g. `let ?currentOutputHandle = stderr in pr "foo"`. – Jon Purdy Nov 27 '16 at 23:49
  • You're right! And I was just looking at this extensions a few hours ago without making the connection. – K. A. Buhr Nov 27 '16 at 23:55