Unison ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ฑํ๊ธฐ ์ํ ์๋ด์, Unison ์ธ์ด์ ๊ธฐ๋ณธ๊ธฐ๋ฅผ ๋น ๋ฅด๊ฒ ํ์ด๋ณผ ์ ์๋ ์์ ๋ชจ์์ ๋๋ค.
URL: https://www.unison-lang.org/docs/
Unison ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ฑํ๊ณ ์ถ๋ค๋ฉด, ์ฌ๊ธฐ ์ค์ ๊ฒ์ด ๋ง์ต๋๋ค. Unison ์ธ์ด์ ์ํ๊ณ๋ ์ฝ๋๋ฅผ ์ฆ๊ฒ๊ฒ ์์ฑํ ์ ์๋๋ก ์ธ์ฌํ๊ฒ ์ค๊ณ๋์์ต๋๋ค.
Unison ์ฝ๋๊ฐ ์ด๋ค ๋ชจ์ต์ธ์ง ๊ฐ์ ์ก๊ณ ์ถ๋ค๋ฉด, ์๋์ ์ผ์์ ์ผ๋ก ์์ฃผ ์ฐ๋ ์ธ์ด ๊ธฐ๋ณธ ์์ ๋ช ๊ฐ์ง์ ๋ ํฌ๊ด์ ์ธ ๋ฌธ์๋ก ์ด์ด์ง๋ ๋งํฌ๋ฅผ ์ค๋นํด ๋์์ต๋๋ค.
์ด ๋ฌธ์๋ ์ค๋ช ์ ์ต์ํํ๊ณ ์ฝ๋ ์กฐ๊ฐ ์์ฃผ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค. ๊ณณ๊ณณ์ ๋ ์์ธํ ๋ฌธ์ ์น์ ์ผ๋ก ๊ฐ๋ ๋งํฌ๊ฐ ์ ๊ณต๋ฉ๋๋ค. ์์ง UCM์ ๋ค์ด๋ก๋ํ์ง ์์๋ค๋ฉด, ๋จผ์ ๊ทธ๊ฑธ ํด๋๋ ๊ฒ ์ข์ ์ ์์ด์. ๐
Unison ์ฝ๋๋ ์ด๋ค .u ํ์ฅ์๋ฅผ ๊ฐ์ง "์คํฌ๋์น" ํ์ผ์๋ ์์ฑํ ์ ์์ต๋๋ค.
๊ณ ์ ์ ์ธ helloWorld ํ๋ก๊ทธ๋จ์ IO ๋ฅ๋ ฅ(ability)์ ํตํด ์ฝ์ ์ํธ์์ฉ์ ์ํํฉ๋๋ค. Unison์์ ability๊ฐ ์ด๋ป๊ฒ ํจ๊ณผ(effect)๋ฅผ ๋ชจ๋ธ๋งํ๋์ง ์ฝ์ด๋ณด์ธ์.
helloWorld : '{IO, Exception} ()
helloWorld = do printLine "Hello World"
ํ๋ก๊ทธ๋จ์ ์ํธ๋ฆฌ ํฌ์ธํธ๋ UCM์ run ๋ช
๋ น์ผ๋ก ์คํํฉ๋๋ค.
scratch/main> project.create hello-world
hello-world/main> run helloWorld
๋๋ update๋ฅผ ์
๋ ฅํด helloWorld ํ๋ก๊ทธ๋จ์ ์ฝ๋๋ฒ ์ด์ค์ ์ถ๊ฐํ ๋ค์, ๋ฐ์ด๋๋ฆฌ ์คํ ํ์ผ๋ก ํจํค์งํ์ฌ ์คํํ ์๋ ์์ต๋๋ค.
hello-world/main> update
hello-world/main> compile helloWorld helloFile
๊ทธ๋ฌ๋ฉด ์ฝ๋๋ฒ ์ด์ค์ ๊ฐ์ ๋๋ ํฐ๋ฆฌ์ helloFile.uc๋ผ๋ ์คํ ํ์ผ์ด ์์ฑ๋ฉ๋๋ค. ์ดํ ํฐ๋ฏธ๋์์ ํ๋ก๊ทธ๋จ์ ์์ํ ์ ์์ต๋๋ค.
$ ucm run.compiled helloFile.uc
๐ Unison ํ๋ก๊ทธ๋จ ์คํ์ ๋ํด ๋ ์์๋ณด๊ธฐ
์๋๋ ๋งค๊ฐ๋ณ์ 1๊ฐ๋ฅผ ๋ฐ๋ ํจ์ double์ ์๊ฐํฉ๋๋ค. ํจ์ ์ ์์ ๋ํ Unison ๊ด๋ก๋ ์ฌ๊ธฐ์์ ์์ธํ ์ค๋ช
ํฉ๋๋ค.
double : Nat -> Nat
double x =
x * 2
> double 4
์คํฌ๋์น ํ์ผ์์ >๋ watch expression์ผ๋ก double ํจ์๋ฅผ ์คํํฉ๋๋ค.
๐ Unison ํฌ์ด์์๋ watch expression๊ณผ ๋ค๋ฅธ ์ํฌํ๋ก ๊ธฐ๋ฅ์ ์๋ดํฉ๋๋ค
Unison์์ ๊ณ์ฐ์ด ์ง์ฐ๋จ์ ๋ํ๋ด๋ ๋ฐฉ๋ฒ์ ๋ช ๊ฐ์ง๊ฐ ์์ต๋๋ค: do, ์ธ๋์ค์ฝ์ด ์ธ์, ๊ทธ๋ฆฌ๊ณ ' ๊ธฐํธ.
main : '{IO, Exception} ()
main = do printLine "hello world"
main : '{IO, Exception} ()
main _ = printLine "hello world"
main : '{IO, Exception} ()
main = '(printLine "hello world")
์ง์ฐ ๊ณ์ฐ ์์ !๋ฅผ ๋ถ์ด๊ฑฐ๋, ๋ค์ ()๋ฅผ ๋ถ์ฌ ํธ์ถํฉ๋๋ค.
greet : '{IO, Exception} ()
greet = do
name = console.readLine()
printLine ("Hello " ++ name)
greet : '{IO, Exception} ()
greet = do
name = !console.readLine
printLine ("Hello " ++ name)
๐ ์ง์ฐ ๊ณ์ฐ์ ๋ํ ๋ ์์ธํ ์ค๋ช
Unison์๋ Text๋ฅผ ๋ถํ (splitting)ํ๊ณ ๊ฒ์(searching)ํ๋ ํจ์๊ฐ ์ฌ๋ฟ ์์ต๋๋ค.
๋ ์ ์ฐํ ์ ๊ท์(regex) ์คํ์ผ์ ํ
์คํธ ํจํด ์์
์๋ Pattern์ ์ฌ์ฉํ์ธ์.
๐ Pattern API์ ๋ ๋ง์ ์์
๋๊ดํธ๋ Unison ๋ฆฌ์คํธ๋ฅผ ๋์ ํฉ๋๋ค.
List.++๋ ๋ฆฌ์คํธ ์ฐ๊ฒฐ(concatenation) ์ฐ์ฐ์์
๋๋ค.
๋ฆฌ์คํธ๋ ๋ค์ํ ํจํด ๋งค์นญ ์ต์ ์ ์ง์ํฉ๋๋ค.
๐ Unison์ ์ผ๋ฐ์ ์ธ ์ปฌ๋ ์ ํ์ ๋ ์์๋ณด๊ธฐ
|> ์ฐ์ฐ์๋ ์ผ์ชฝ ํํ์์ ์คํํ ๊ฒฐ๊ณผ๋ฅผ ์ค๋ฅธ์ชฝ ํจ์์ ์ธ์๋ก ์ ๋ฌํ๋ "ํ์ดํ(pipe)"์
๋๋ค.
๊ดํธ๋ก ๊ฐ์ผ x -> x * 100์ List.map์ ์ ๋ฌ๋๋ ์ธ์๋ก, Unison์ ๋๋ค(lambda) ๋ฌธ๋ฒ์ ์์
๋๋ค.
๐ |> ๊ฐ์ ์ฐ์ฐ์ ๋ ์์๋ณด๊ธฐ
์๋ ํํ์์ if then else ๋ฌธ๋ฒ๊ณผ ํจํด ๋งค์นญ ๋ฌธ๋ฒ ๋ ๋ฐฉ์์ผ๋ก ์์ฑ๋์ด ์์ต๋๋ค.
isEven num =
if mod num 2 === 0 then "even" else "odd"
isEven num = match num with
n | mod n 2 === 0 -> "even"
_ -> "odd"
Unison์ ํจํด ๋งค์นญ ๊ธฐ๋ฅ์๋ ๋ณ์ ๋ฐ์ธ๋ฉ, ํจํด ๊ฐ๋(|๋ก ๊ตฌ๋ถ), ๊ทธ๋ฆฌ๊ณ as-ํจํด(@๋ก ํ๊ธฐ)์ด ํฌํจ๋ฉ๋๋ค.
match Some 12 with
Optional.None -> "none"
Some n| Nat.isEven n -> "n is a variable and | is a pattern guard"
opt@(Some n) -> "opt binds to the entire optional value"โงจ"n is a variable and | is a pattern guard"
cases ๋ฌธ๋ฒ์ ์ ์ฒด match ... with ํํ์์ ๋์ฒดํ ์ ์์ต๋๋ค.
foo n = match n with
0 -> "zero"
_ -> "not zero"
foo = cases
0 -> "zero"
_ -> "not zero"
๐ Unison์ ํจํด ๋งค์นญ ๋ฌธ๋ฒ ๋ ์์๋ณด๊ธฐ
์ด๋ฆ์ผ๋ก ์ ์ผ์ฑ์ด ๊ฒฐ์ ๋๋ Unison ๋ฐ์ดํฐ ํ์ :
type LivingThings
= Animal
| Plant
| Fungi
| Protists
| Monera
๋จ์ผ ํ์ ๋งค๊ฐ๋ณ์๋ฅผ ๊ฐ๋ ์ฌ๊ท์ Tree ๋ฐ์ดํฐ ํ์ :
structural type Tree a
= Empty
| Node a (Tree a) (Tree a)
structural ํค์๋๋ ๊ฐ์ ๊ตฌ์กฐ๋ก ์ ์๋ ํ์
๋ค์ด ๋์ผํ๋ค๋ ๋ป์
๋๋ค.
๋ฐ์ดํฐ ํ์ ๊ณผ structural ํ์ /unique ํ์ ์ ์ฐจ์ด์ ๋ํด ๋ ์์๋ณด๊ธฐ
๋ ์ฝ๋ ํ์ (record type)์ ํ์ ์ ํ๋์ ์ด๋ฆ์ ๋ถ์ผ ์ ์๊ฒ ํด์ค๋๋ค.
type Pet = {
age : Nat,
species : Text,
foodPreferences : [Text]
}
๋ ์ฝ๋ ํ์ ์ ์์ฑํ๋ฉด ๋ฐ์ดํฐ ํ์ ์ ํ๋์ ์ ๊ทผํ๊ณ ์ ๋ฐ์ดํธํ๊ธฐ ์ํ ์ฌ๋ฌ ํฌํผ ๋ฉ์๋๊ฐ ํจ๊ป ์์ฑ๋ฉ๋๋ค.
scratch/main> add Pet
โ I've added these definitions:
unique type Pet
Pet.age : Pet -> Nat
Pet.age.modify : (Nat ->{g} Nat) -> Pet ->{g} Pet
Pet.age.set : Nat -> Pet -> Pet
๐ ๋ ์ฝ๋ ํ์ ๋ฌธ๋ฒ ์ฌํ
์์ธ๋ Exception ability๋ก "๋ฐ์(raise)"์ํค๊ณ , ํธ๋ค๋ฌ๋ก "์ก์(catch)" ์ฒ๋ฆฌํฉ๋๋ค.
ability๋ Unison์์ ํจ๊ณผ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
์๋๋ Random ability๋ฅผ ์ฌ์ฉํ๋ ํจ์์ธ natIn์ผ๋ก ๋ฆฌ์คํธ์์ ์ธ๋ฑ์ค๋ก ์์์ ์์๋ฅผ ๋ฝ์์ต๋๋ค. ์ธ๋ฑ์ค๊ฐ ๋ฆฌ์คํธ์ ์์ผ๋ฉด Abort ability๋ฅผ ์ฌ์ฉํด ์คํ์ ์ค๋จํฉ๋๋ค.
splitmix์ toOptional!์ ability ํธ๋ค๋ฌ์ ์์
๋๋ค.
๐ ability์ ๋ํ ๋ฉํ ๋ชจ๋ธ ์ดํดํ๊ธฐ
Unison์์๋ ํน๋ณํ ๋ฌธ๋ฒ์ด๋ ์ธ๋ถ ํ๋ ์์ํฌ ์์ด๋ Remote ability๋ฅผ ํตํด ์ธ์ด ์์ฒด์์ ๋ถ์ฐ ๊ณ์ฐ์ ํํํ ์ ์์ต๋๋ค.
Remote ability์ ๊ทธ ๊ธฐ๋ฅ์ ๋ํด ์ฝ์ด๋ณด๊ธฐ
forkedTasks : '{Remote} Nat
forkedTasks = do
task1 = Remote.fork here! do
1 + 1
task2 = Remote.fork here! do
2 + 2
Remote.await task1 + Remote.await task2
์ด ์์ ๋ ๋ ๊ฐ์ ๊ณ์ฐ์ ์๊ฒฉ์ผ๋ก ์คํํ๋๋ก forkํ ๋ค, ๊ฒฐ๊ณผ๋ฅผ awaitํ์ฌ ๊ฒฐํฉํฉ๋๋ค.
๐ ๋ ์์ฑ๋ ๋์ ๋ถ์ฐ ์ฌ์ฉ ์ฌ๋ก๋ ์ด ๊ธ์์ ์์ธํ ๋ค๋ฃน๋๋ค
lib.install ๋ช
๋ น์ผ๋ก Unison Share์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
myProject/main> lib.install @unison/http
๋จผ์ URI๋ฅผ ํ์ฑํ ๋ค์, Http.get์ ์ ๋ฌํ์ฌ HTTP ์๋ต์ ๊ฐ์ ธ์ต๋๋ค. ์์ฒญ์ Http ํธ๋ค๋ฌ์ ์ ๋ฌํจ์ผ๋ก์จ ์คํ๋ฉ๋๋ค.
๐ ๋ ๋ง์ ์์ ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฌธ์๋ฅผ ํ์ธํ์ธ์
readFileUtf8 : FilePath ->{IO, Exception} TextFilePath.writeFile : FilePath -> Bytes ->{IO, Exception} ()renameFile : FilePath -> FilePath ->{IO, Exception} ()
ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์๋ ์ ์ฉํ File ์์
์ด ๋ค์ ๋ด์ฅ๋์ด ์์ต๋๋ค. ์ด๋ค์ FilePath ๋ฐ Handle ๋ค์์คํ์ด์ค ์๋์ ์์ต๋๋ค.
MVar, TVar, STM ๊ฐ์ ๋์์ฑ ๊ธฐ๋ณธ ์์๋ ๋ฒ ์ด์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ด์ฅ๋์ด ์์ต๋๋ค. TVar์ STM์ ๋ฝ ์์ด(lock-free) ๋์ ์ ๊ทผ ๊ฐ๋ฅํ ๊ฐ๋ณ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ฝ๊ฒ ์์ฑํ ์ ์๊ฒ ํด์ค๋๋ค. ์๋ฅผ ๋ค์ด ์๋๋ ๊ฐ๋จํ ๋ฝ-ํ๋ฆฌ ํ ๊ตฌํ๊ณผ ๋ช ๊ฐ์ง ํฌํผ ํจ์์
๋๋ค:
type STM.TQueue a = TQueue (TVar [a]) (TVar Nat)
์๋์ STM.atomically๊ฐ ๋์
ํ๋ ๋ธ๋ก์, ๋ธ๋ก ์์ ์ก์
๋ค์ด ์ํ๋ ๋๊น์ง ํ์ ์ํ์ ๋๊ตฌ๋ ์ ๊ทผํ ์ ์๋๋ก ๋ณด์ฅํฉ๋๋ค.