sml - A curry function that executes another function n times -
i'm solving old exam practice sml. 1 task found interesting was: write function repeat
executes function signature 'a -> 'a.
i assumed requested function curry function , used o
-operator:
fun repeat (1, f: 'a->'a) = f | repeat (n, f: 'a->'a) = f o repeat (n-1, f);
however, o
operator not formally introduced in out course, , wonder how write without it?
not less verbose, in way, explicit, after, less verbose, explanations.
a curried function function getting single argument. if expression has more arguments, there many nested functions. first outer level function gets argument, , made of inner level function may it‑self made of inner function, , on. of inner level function may returned, not innermost, explained later (this kind of “partial evaluation”). inner function “specialized” arguments (formally, arguments bound in closure) of outer functions.
we know there @ least function argument f
, integer argument counter
. there needs argument seed
also, invoke function f
first time.
the order of nesting may arbitrary or specified. if not specified, prefer put least varying arguments on outer‑scope , varying in inner‑scope. here, is, least varying: f
, counter
seed
.
this enough suggest beginning of template:
val repeat: ('a -> 'a) -> int -> 'a -> 'a = fn f: 'a -> 'a => fn count: int => fn seed: 'a => …
we implemented ('a -> 'a) -> int -> 'a
part of signature. remains last -> 'a
means 'a
returned, , evaluated inner loop.
a loop may of form (in pseudo‑code):
val rec loop = fn => if condition-to-stop return-something-or-`()` else loop (i + 1) or (i - 1)
if loop compute something, need argument acting accumulator, , return accumulator final result.
implementing loop , putting inside curried function template above, get:
val repeat: ('a -> 'a) -> int -> 'a -> 'a = fn f: 'a -> 'a => fn count: int => fn seed: 'a => let val rec loop = fn (counter, x) => if counter <= 0 x else loop (counter - 1, f x) in loop (count, seed) end
do understand let … in … end
construct here?
note guard on counter
may use pattern did, sml's integer may negative (there no strict natural in sml), that's safer catch case too, if … … else
instead of pattern matching. mileage may vary on point, that's not question's focus.
the same above, using fun
instead of val rec
:
fun repeat (f: 'a -> 'a) (count: int) (seed: 'a): 'a = let fun loop (counter, x) = if counter <= 0 x else loop (counter - 1, f x) in loop (count, seed) end
note repeat
arguments not separated ,
(neither *
). way write curried function using fun
(on contrary, loop
not curried). compare prior val
version of same function. if no type specified , names, parenthesis can omitted.
a test function used f
argument:
val appendanx = fn s: string => s ^ "x"
the test:
val () = print (repeat appendanx 5 "blah:")
curried function more abstract function getting tuple (which formally single argument, makes curried function too, that's story , bit cheating), outer function(s) may partially applied:
this partial application, leaving last argument, seed
, unbound:
val repeatappendanxthreetimes = repeat appendanx 3
then function may applied specifiying seed
:
val () = print (repeatappendanxthreetimes "blah:")
similarly, both counter
, seed
may left free:
val repeatappendanx = repeat appendanx val () = print (repeatappendanx 4 "blah:")
another way of defining repeatappendanxthreetimes
. compare other definition above:
val repeatappendanxthreetimes = repeatappendanx 3 val () = print (repeatappendanxthreetimes "blah:")
Comments
Post a Comment