무냐의 개발일지
[OSSU] <Programming Language, Part A> / Week4 본문
함수 자체를 인수로 넣는 거!
First-Class function : 다른 함수의 인수로 아무데나 넣을 수 있는 성질의 함수 : 고차 함수 (higher-order funciton)
Function Closure : First-class function 만들고 나서, 이걸 인수, local variable, 환경에 있는 것들 다 사용할 수 있는 함수
| Anonymous function
1)
fun triple x = 3*x
fun triple_n_times1 (n,x) = n_times(triple,n,x)
2)
fun triple_n_times2 (n,x) =
let fun triple x = 3*x in n_times(triple,n,x) end
3)
fun triple_n_times3 (n,x) =
n_times((let fun triple y = 3*y in triple end), n, x)
4)
fun triple_n_times4 (n,x) = n_times((fn y => 3*y), n, x)
마지막 방식으로 코드를 짜는게 제일 깔끔하다!!
let in end 식으로 써야 binding이 아니라 expression이 돼서 코드가 작동하는데
이거를 fn y => 3*y 이런 식으로 쓸 수도 있다 .얘는 함수 이름을 지어줄 수 없으니까 그냥 fn 과 변수로 써준다
Anonymous functions are expressed in the form 𝑓𝑛 [𝑎𝑟𝑔𝑢𝑚𝑒𝑛𝑡𝑠]=>[𝑓𝑢𝑛𝑐𝑡𝑖𝑜𝑛 𝑏𝑜𝑑𝑦]. The answer 𝑓𝑛 𝑥=>𝑥+3 is of this form where 𝑥 is the [𝑎𝑟𝑔𝑢𝑚𝑒𝑛𝑡𝑠] and 𝑥+3 is the [𝑓𝑢𝑛𝑐𝑡𝑖𝑜𝑛 𝑏𝑜𝑑𝑦].
한 곳에만 이 특정 함수가 필요한 경우라면 anonymous function(익명의 이름없는 함수)를 쓰는게 더 간편해!!
| 쓰잘데기 없는 function wrapping
(* bad style: the if e then true else false of functions *)
fun nth_tail (n,xs) = n_times((fn y => tl y), n, xs)
(* good style: *)
fun nth_tail (n,x) = n_times(tl, n, x)
(* bad style *)
fun rev xs = List.rev xs
val rev = fn xs => List.rev xs
(* good style *)
val rev = List.rev
tl, rev 자체가 기능이 있으니까, 그대로 쓰는거다
open List
이렇게 치면 List에 내장된 모든 함수 확인 가능
| Map, Filter (매우 중요하고, 자주 쓰임)
Famous High-order function !!!
map ; 하나의 함수를 여러개에 다 적용시키는 것
filter ; true인 애들만 남기고, 걸러내는것
fun map (f,xs) =
case xs of
[] => []
| x::xs' => (f x)::(map(f,xs'))
val x2 = map (hd, [[1,2],[3,4],[5,6,7]])
fun filter (f,xs) =
case xs of
[] => []
| x::xs' => if f x
then x::(filter (f,xs'))
else filter (f,xs')
fun all_even xs =
filter(is_even,xs)
predicates : bool을 return하는 표현식
| Lexical Scope
국지적인 정의
(* second example *)
fun f g =
let
val x = 3
in
g 2
end
val x = 4
fun h y = x + y
val z = f h
여기서 일단 x=3는 본문에 쓰이지 않으니까, 쓸데없는 정의가 된다
fun h y = x + y
이거는 fun h y = 4 + y 가 된다
마지막 val z = f h
val z = f h (h 는 4를 더하는 함수지)
val z = f + 4
여기서 f g 는 그냥 g 2 를 부르는 함수네,
그러면 f 는 그냥 2를 부를테니까
val z = 2 + 4 = 6이 된다
| Currying
자꾸만 카레를 떠올리게 하는 이름인데...
합성함수를 표현하는 방식이다. 고딩때 배웠던 딱 그 표기법
(* ('b -> 'c) * ('a -> 'b) -> ('a -> 'c) : function composition (합성함수) *)
fun compose (f,g) = fn x => f (g x)
fun sqrt_of_abs i = Math.sqrt(Real.fromInt (abs i))
fun sqrt_of_abs i = (Math.sqrt o Real.fromInt o abs) i
val sqrt_of_abs = Math.sqrt o Real.fromInt o abs
가장 오른쪽의 abs 부터 오른쪽으로 쭉 빠져나오면서 적용되는 것
이걸 왼쪽부터 읽고싶어서 만들어낸 infix
보통 | > 요렇게 생겨먹은걸로 많이 쓴다
(* tells the parser !> is a function that appears between its two arguments *)
infix !>
(* operator more commonly written |>, but that confuses the current version
of SML Mode for Emacs, leading to bad editing and formatting *)
(* definition of the pipeline operator *)
fun x !> f = f x
(*오른쪽에서 왼쪽으로 읽지 않고, 편하게 왼쪽에서부터 따라가게 만들어주는 장치임*)
fun sqrt_of_abs i = i !> abs !> Real.fromInt !> Math.sqrt
fun backup1 (f,g) = fn x => case f x of
NONE => g x
| SOME y => y
(* 어떤 에러라도 뜨면 g를 내놔라 *)
fun backup2 (f,g) = fn x => f x handle _ => g x
| Closure and Recomputation
(*매번 부른다. s의 사이즈를 구하는 걸 비교할때마다 한다. list의 length 횟수만큼 한다*)
fun allShorterThan1 (xs,s) =
filter (fn x => String.size x < (print "!"; String.size s), xs)
(*local var i 를 만든다. 답은 1번과 같지만, list가 길어질수록 이게 더 효율적임
s의 사이즈를 구하는 걸 1번만 한다*)
fun allShorterThan2 (xs,s) =
let
val i = (print "!"; String.size s)
in
filter(fn x => String.size x < i, xs)
end
아래의 경우가 local variable이 있는 경우로, 더 효율적임
let binding을 한번만 돌린거임 ( No Recomputation )
| FOLD
| Function Composition (합성함수)
오른쪽에서 왼쪽으로 읽는거다
(* ('b -> 'c) * ('a -> 'b) -> ('a -> 'c) : function composition (합성함수) *)
fun compose (f,g) = fn x => f (g x)
fun sqrt_of_abs i = Math.sqrt(Real.fromInt (abs i))
fun sqrt_of_abs i = (Math.sqrt o Real.fromInt o abs) i
val sqrt_of_abs = Math.sqrt o Real.fromInt o abs
Pipeline
* 오른쪽에서 왼쪽으로 읽지 않고, 편하게 왼쪽에서부터 따라가게 만들어주는 장치임*
똑같은 펑션임
fun backup1 (f,g) = fn x => case f x of
NONE => g x
| SOME y => y
(* 어떤 에러라도 뜨면 g를 내놔라 *)
fun backup2 (f,g) = fn x => f x handle _ => g x
| Currying
Currying is a technique in functional programming that allows you to transform a function that takes multiple arguments into a sequence of functions that each take one argument. This can make your code more readable, reusable, and modular, as well as enable partial application and higher-order functions.2023. 10. 18.
웬만하면 모든 언어가 다 curried 된 상태임
| Mutable References
z -> x 를 가리키므로 같은 걸 가리킨다
:= 는 값을 바꾸는거다. val _ = x := 43 은 곧 x를 43으로 바꾸겠다는 것
마지막에 w는 y는 42그대로고 z는 x값이 바뀌었으므로 z도 그대로 바뀐게 되기 때문에 43 ==> 85
| CallBacks
ML에서 많이 나오는데, 말 그대로 코드를 돌렸을 때 실행한 시간이나 횟수를 세는 함수 역할을 한다
파이썬에서 tqdm이 시간을 세는건데 이건 콜백은 아니지만 유사해보인다
(* Programming Languages, Dan Grossman *)
(* Section 3: Callbacks *)
(* these two bindings would be internal (private) to the library *)
val cbs : (int -> unit) list ref = ref []
fun onEvent i =
let fun loop fs =
case fs of
[] => ()
| f::fs' => (f i; loop fs')
in loop (!cbs) end
(* clients call only this function (public interface to the library) *)
fun onKeyEvent f = cbs := f::(!cbs)
(*callbacks =assign= one more element + (previous) *)
(* some clients where closures are essential
notice different environments use bindings of different types
*)
val timesPressed = ref 0
val _ = onKeyEvent (fn _ => timesPressed := (!timesPressed) + 1)
fun printIfPressed i =
onKeyEvent (fn j => if i=j
then print ("you pressed " ^ Int.toString i ^ "\n")
else ())
val _ = printIfPressed 4
val _ = printIfPressed 11
val _ = printIfPressed 23
val _ = printIfPressed 4
onEvent 11
!timesPressed
onEvent 13
!timesPressed
onEvent 79
!timesPressed
(*v
al it = () : unit
-
val it = 1 : int
-
val it = 1 : int
-
val it = () : unit
-
val it = 2 : int
-
val it = () : unit
-
val it = 3 : int*)
List.last
val it = fn : 'a list -> 'a
-
List.map
val it = fn : ('a -> 'b) -> 'a list -> 'b list
structure x = List
signature x = LIST
이렇게 하면 리스트의 모든 함수가 나온다
'OSSU_CS coursework' 카테고리의 다른 글
[OSSU] <Programming Language, Part A> / Week5 (0) | 2024.05.30 |
---|---|
[OSSU] <Programming Language, Part A> / Week3 (0) | 2024.05.23 |
[OSSU] <Programming Language, Part A> / Week2 (0) | 2024.05.19 |
[OSSU] <Programming Language, Part A> / Week1 _SML/NJ 설치 방법 (오류 수정) (0) | 2024.05.18 |
[OSSU] <UBCx HtC1x_How to Code> / 10_Accumulator (0) | 2024.05.11 |