The difference between "local" and "let" in SML

I could not find a friendly answer for beginners about the difference between “local” and “let” keywords in SML. Can someone provide a simple example, please, and explain when it is used over another?

+4
source share
2 answers

(TL; DR)

  • Use case ... of ...when you have only one time reference.
  • Use let ... in ... endfor very specific helper functions.
  • Never use local ... in ... end. Use opaque modules instead.

sepp2k:

  • (Summary) local ... in ... end - , let ... in ... end - , , : (, ) (val fun) .

    ? , . , Rosetta Stone QuickSort , :

    (* First using local ... in ... end *)
    local
        fun par_helper([], x, l, r) = (l, r)
          | par_helper(h::t, x, l, r) =
              if h <= x
                then par_helper(t, x, l @ [h], r)
                else par_helper(t, x, l, r @ [h])
    
        fun par(l, x) = par_helper(l, x, [], [])
    in
      fun quicksort [] = []
        | quicksort (h::t) =
            let
              val (left, right) = par(t, h)
            in
              quicksort left @ [h] @ quicksort right
            end
    end
    
    (* Second using let ... in ... end *)
    fun quicksort [] = []
      | quicksort (h::t) =
          let
            fun par_helper([], x, l, r) = (l, r)
              | par_helper(h::t, x, l, r) = 
                  if h <= x
                    then par_helper(t, x, l @ [h], r)
                    else par_helper(t, x, l, r @ [h])
    
            fun par(l, x) = par_helper(l, x, [], [])
    
            val (left, right) = par(t, h)
          in
            quicksort left @ [h] @ quicksort right
          end
    

, .

  • local ... in ... end , (, ), , . .

    (* Helper function shared across multiple functions *)
    local
        fun par_helper ... = ...
    
        fun par(l, x) = par_helper(l, x, [], [])
    in
      fun quicksort [] = []
        | quicksort (h::t) = ... par(t, h) ...
    
      fun median ... = ... par(t, h) ...
    end
    

    , let ... in ... end .

    local ... in ... end (. ).

  • let ... in ... end , (, ), . .

    fun quicksort [] = []
      | quicksort (x::xs) =
        let
          val (left, right) = List.partition (fn y => y < x) xs
        in
          quicksort left @ [x] @ quicksort right
        end
    

    let ... in ... end:

    • ( ).
    • ( left right ).
    • . ( , local ... in ... end.)
    • .
    • , , .


    ... , let- .

    , let ... in ... end.

    , .

  • (case ... of ... .)

    let ... in ... end, , .

    fun quicksort [] = []
      | quicksort (x::xs) =
        case List.partition (fn y => y < x) xs of
          (left, right) => quicksort left @ [x] @ quicksort right
    

    . . case ... of ... , , ('a option, 'a list ..),

    (* Using case ... of ... *)
    fun maxList [] = NONE
      | maxList (x::xs) =
        case maxList xs of
             NONE => SOME x
           | SOME y => SOME (Int.max (x, y))
    
    (* Using let ... in ... end and a helper function *)
    fun maxList [] = NONE
      | maxList (x::xs) =
        let
          val y_opt = maxList xs
        in
          Option.map (fn y => Int.max (x, y)) y_opt
        end
    

    case ... of ...: , . -, .

    fun move p1 (GameState old_p) gameMap =
        let val p' = addp p1 old_p in
          case getMapPos p' gameMap of
              Grass => GameState p'
            | _     => GameState old_p
        end
    

    , local ... in ... end.

  • , , . .

    (* if they're overly specific *)
    fun handvalue hand =
        let
          fun handvalue' [] = 0
            | handvalue' (c::cs) = cardvalue c + handvalue' cs
          val hv = handvalue' hand
        in
          if hv > 21 andalso hasAce hand
          then handvalue (removeAce hand) + 1
          else hv
        end
    
    (* to cover over multiple arguments, e.g. to achieve tail-recursion, *)
    (* or because the inner function has dependencies anyways (here: x). *)
    fun par(ys, x) =
        let fun par_helper([], l, r) = (l, r)
              | par_helper(h::t, l, r) =
                  if h <= x
                    then par_helper(t, l @ [h], r)
                    else par_helper(t, l, r @ [h])
        in par_helper(ys, [], []) end
    

    . ,

    • (, ) , .
    • , local ... in ... end let ... in ... end .
  • (local ... in ... end .)

    local ... in ... end. , , , , , , .

    , . , .

    j4cbo SML - Stilts StaticServer: val server : ..., structure U = WebUtil val content_type = ....

    structure StaticServer :> sig
    
      val server: { basepath: string,
                    expires: LargeInt.int option,
                    headers: Web.header list } -> Web.app
    
    end = struct
    
      structure U = WebUtil
    
      val content_type = fn
            "png" => "image/png"
          | "gif" => "image/gif"
          | "jpg" => "image/jpeg"
          | "css" => "text/css"
          | "js" => "text/javascript"
          | "html" => "text/html"
          | _ => "text/plain" 
    
      fun server { basepath, expires, headers } (req: Web.request) = ...
    end
    
+4

: local , let . , , local in end, let . .

@SimonShine, local .

+3

Source: https://habr.com/ru/post/1655092/


All Articles