지하성과 용과 편지
61003 단어 functionalocaml
Dell은 다음과 같은 이점을 제공합니다.
1) 문자는 다음과 같이 표시됩니다.
그의 이름
이 해결 방안의 목적은 OCAml 편지를 보여주고 OCAml에서 S.O.L.I.D 원칙을 응용하는 데 어떻게 도움이 되는지 보여주는 것이다.
이 글은 나의 블로그 글의 번역: https://oteku.github.io/ocaml-functors/(FR)
DnD 정보
Dunjon & Dragons a.k.a DnD는 캐릭터 플레이 게임으로 게이머들이 환상적인 장면에서 영웅을 연기한다.
이 게임의 주요 설정은 필른, 아벨토리 별의 대륙이다.
오픈 게임 라이센스(OGL)에 따라 Dungeons & Dragons 5th Edition System을 사용할 예정입니다.
우리는 드워프
우선 드워프의 이름으로 드워프를 모의하고 싶은데, 이 종족 중 하나야.
우리는 OCAml에서 명칭 공간을 가진 좋은 방법 중 하나가 모듈을 사용하는 것이라고 알고 있기 때문에 다음과 같은 표시부터 시작할 수 있다.
module Dwarf = struct
type t = string
end
이 실현에서 모듈의 유형을 추정합니다.또한 모듈 서명을 추가하고 Elves를 모델링하여 명확히 할 수도 있습니다.module Dwarf : sig
type t = string
end = struct
type t = string
end
module Elf : sig
type t = string
end = struct
type t = string
end
이 단계에서, 우리는 이 두 모듈이 같은 서명을 공유하는 것을 알아차렸다.정령과 드워프 모듈은 모두 영웅을 놀 수 있는 것을 대표하기 때문에 이것은 합법적인 것 같다. 우리는 모든 영웅이 같은 서명을 가지고 있다는 것을 명확히 지적해야 한다.이를 위해 모듈 유형을 사용할 수 있습니다.module type PLAYABLE = sig
type t = string
end
module Dwarf : PLAYABLE = struct
type t = string
end
module Elf : PLAYABLE = struct
type t = string
end
다른 모듈은 PLAYABLE.t
의 형상을 알 필요가 없다. 그들은 그것이 존재하는지만 알고 모듈은 그 함수를 공개적으로 사용해야 한다.우리는 추상이라고 부른다.
module type PLAYABLE = sig
type t
val to_string : t -> string
val of_string : string -> t
end
이제 PLAYABLE 유형의 각 모듈에서 이러한 기능을 수행해야 합니다.이제 시작하겠습니다.module Dwarf : PLAYABLE = struct
type t = {name : string}
let to_string dwarf = dwarf.name
let of_string name = {name}
end
module Elf : PLAYABLE = struct
type t = string
let to_string elf = elf
let of_string name = name
end
t
은 추상적이기 때문에 PLAYABLE
을 실현하는 모듈마다 t
의 구체적인 유형이 다를 수 있음을 알 수 있습니다.그들이 모듈 유형 계약을 존중할 때, 이것은 완전히 좋은 것이다.다른 모듈에서는 구체적인 값
t
에 접근할 수 없지만, 우리는 난쟁이를 만들거나 문자열 표시를 가져올 수 있습니다.let gimly = Dwarf.of_string "Gimly"
let () = Dwarf.to_string gimply |> print_endline
영웅은 능력이 있다
DnD에서도 영웅은 그 능력으로 표현된다.
만들 때 여러 개의 능력 옵션 규칙이 있습니다. 표준 점수 1만 실행합니다.시작할 때 각 능력의 값은 10이다.
module Abilities = struct
type t = {
strength : int
; dexterity : int
; constitution : int
; intelligence : int
; wisdom : int
; charisma : int
}
let init () = {
strength = 10
; dexterity = 10
; constitution = 10
; intelligence = 10
; wisdom = 10
; charisma = 10
}
end
우리는 다음과 같은 방식으로 우리의 난쟁이 모듈을 업그레이드할 수 있다.module Dwarf: PLAYABLE = struct
type t = {name : string ; abilities : Abilities.t}
let to_string dwarf = dwarf.name
let of_string name = {name ; abilities = Abilities.init()}
end
함수 이름이 논리에 맞지 않으므로 PLAYABLE
모듈 유형을 업데이트한 다음 Elf
및 Dwarf
모듈을 업데이트합니다.module type PLAYABLE = sig
type t
val name : t -> string
val make : string -> t
end
module Dwarf: PLAYABLE = struct
type t = {name : string ; abilities : Abilities.t}
let name dwarf = dwarf.name
let make name = {name ; abilities = Abilities.init()}
end
module Elf: PLAYABLE = struct
type t = {name : string ; abilities : Abilities.t}
let name elf = elf.name
let make name = {name ; abilities = Abilities.init()}
end
종족 부여 수식어
다프 부부 변비 보상 +2.
Ocaml에서 모듈은 일류입니다. 이것은 모듈을 값으로 사용할 수 있음을 의미합니다.따라서 상금을 표시하는 새로운 모듈 유형을 만들고 함수를 만들어 2의 상금을 표시할 수 있습니다.
module type BONUS = sig
type t
val value : t
end
let bonus_2 : (module BONUS with type t = int) = (module struct
type t = int
let value = 2
end)
bonus_2
은 하나의 모듈을 값으로 한다.t
은 추상적이기 때문에 우리는 유형 증인 with type t = int
을 추가해야 한다.상금의 가치를 풀려면 Getter가 필요합니다.
let get_bonus b = let module M = (val (b : (module BONUS with type t = int))) in M.value
If you need more explaination about First-Class, you should read : https://dev.realworldocaml.org/first-class-modules.html
이제 우리는 다음과 같이 쓸 수 있다.
module Dwarf: PLAYABLE = struct
type t = {name : string ; abilities : Abilities.t}
let name dwarf = dwarf.name
let make name = {name ; abilities = Abilities.init()}
let constitution dwarf = dwarf.abilities.constitution + get_bonus bonus_2
end
그리고 요정, 오크, 반인, 철피인
드워프는 프론의 유일한 종족이 아니오.사람마다 체질 보너스가 다르다.오크는 +1이 있고, 정령, 반인, 철기는 체질 보너스가 없다.
함수 중의 데이터가 변할 때, 우리는 코드가 중복되지 않도록 함수 파라미터를 추가할 것이다.우리는 모듈급에서 같은 일을 할 수 있다.Ocaml은 기능 모듈의 편지를 제공합니다: 한 모듈에서 다른 모듈로의 함수입니다.
그래서 우리는
Race
편지를 만들 수 있다.module Race (B : BONUS with type t = int) : PLAYABLE = struct
type t = {name : string ; abilities : Abilities.t}
let name character = character.name
let make name = {name ; abilities = Abilities.init()}
let constitution_bonus = B.value (* here we get the value from module B *)
let constitution character = character.abilities.constitution + constitution_bonus
end
함수 Race
은 B
유형의 모듈 BONUS
(t
유형은 int
)을 매개 변수로 하고 PLAYBLE
유형의 모듈로 되돌아갈 수 있습니다.이렇게 하면 우리는 우리의 모듈을 쉽게 보유할 수 있다.
(* we add a function to manage all bonus *)
let bonus (x:int) : (module BONUS with type t = int) = (module struct
type t = int
let value = x
end)
(* we use our Race functor to create the five races *)
module Dwarf = Race (val bonus 2)
module Elf = Race (val bonus 0)
module Tiefling = Race (val bonus 0)
module Halfling = Race (val bonus 0)
module HalfOrc = Race (val bonus 1)
모든 스킬에 추가 보상이 있을 수 있습니다
편지는 하나의 매개 변수에 국한되지 않기 때문에 우리는 같은 기교를 사용하여 모든 보너스를 관리할 수 있다.
module Race
(BS : BONUS with type t = int)
(BD : BONUS with type t = int)
(BC : BONUS with type t = int)
(BI : BONUS with type t = int)
(BW : BONUS with type t = int)
(BCh : BONUS with type t = int) : PLAYABLE = struct
type t = {name : string ; abilities : Abilities.t}
let name character = character.name
let make name = {name ; abilities = Abilities.init()}
let bonus = Abilities.{
strength = BS.value
; dexterity = BD.value
; constitution = BC.value
; intelligence = BI.value
; wisdom = BW.value
; charisma = BCh.value
}
let abilities character = Abilities.{
strength = character.abilities.strength + bonus.strength
; dexterity = character.abilities.dexterity + bonus.dexterity
; constitution = character.abilities.constitution + bonus.constitution
; intelligence = character.abilities.intelligence + bonus.intelligence
; wisdom = character.abilities.wisdom + bonus.wisdom
; charisma = character.abilities.charisma + bonus.charisma
}
end
module Dwarf = Race (val bonus 0) (val bonus 0) (val bonus 2)(val bonus 0) (val bonus 0) (val bonus 0)
당신의 용례에 대해 말하자면, 그것은 그렇게 편리하지 않으니, 우리는 반드시 상금의 순서를 기억해야 한다.Dell은 Abilities.t
이 아닌 int
의 모든 역량을 나타냅니다.(* just create a bonus function that take a Abilities.t and return a Bonus module *)
let bonus (x:Abilities.t) : (module BONUS with type t = Abilities.t) = (module struct
type t = Abilities.t
let value = x
end)
(* the functor `Race` take a module `B` of type `BONUS` whom type `t` is `Abilities.t`
** as parameter and then return a module of type `PLAYBLE` *)
module Race
(B : BONUS with type t = Abilities.t) : PLAYABLE = struct
type t = {name : string ; abilities : Abilities.t}
let name character = character.name
let make name = {name ; abilities = Abilities.init()}
let bonus = Abilities.{
strength = B.value.strength
; dexterity = B.value.dexterity
; constitution = B.value.constitution
; intelligence = B.value.intelligence
; wisdom = B.value.wisdom
; charisma = B.value.charisma
}
let abilities character = Abilities.{
strength = character.abilities.strength + bonus.strength
; dexterity = character.abilities.dexterity + bonus.dexterity
; constitution = character.abilities.constitution + bonus.constitution
; intelligence = character.abilities.intelligence + bonus.intelligence
; wisdom = character.abilities.wisdom + bonus.wisdom
; charisma = character.abilities.charisma + bonus.charisma
}
end
(* create our Dwarf module *)
module Dwarf = Race (val bonus Abilities.{
strength = 0
; dexterity = 0
; constitution = 2
; intelligence = 0
; wisdom = 0
; charisma = 0
})
더욱 간결하고 명확해지기 위해서 우리는 no_bonus
값부터 계산할 수 있다.let no_bonus = Abilities.{
strength = 0
; dexterity = 0
; constitution = 0
; intelligence = 0
; wisdom = 0
; charisma = 0
}
module Dwarf = Race (val bonus Abilities.{
no_bonus with constitution = 2
})
module Elf = Race (val bonus Abilities.{
no_bonus with dexterity = 2
})
module Halfling = Race (val bonus Abilities.{
no_bonus with dexterity = 2
})
module Tiefling = Race (val bonus Abilities.{
no_bonus with charisma = 2 ; intelligence = 1
})
module HalfOrc = Race (val bonus Abilities.{
no_bonus with strength = 2
})
요약
이 절의 말미에 너는 반드시 다음과 같이 있어야 한다.
module Abilities = struct
type t = {
strength : int
; dexterity : int
; constitution : int
; intelligence : int
; wisdom : int
; charisma : int
}
let init () = {
strength = 10
; dexterity = 10
; constitution = 10
; intelligence = 10
; wisdom = 10
; charisma = 10
}
end
module type BONUS = sig
type t
val value : t
end
let bonus (x:Abilities.t) : (module BONUS with type t = Abilities.t) =
(module struct
type t = Abilities.t
let value = x
end)
let no_bonus = Abilities.{
strength = 0
; dexterity = 0
; constitution = 0
; intelligence = 0
; wisdom = 0
; charisma = 0
}
module type PLAYABLE = sig
type t
val make : string -> t
val name : t -> string
val abilities : t -> Abilities.t
end
module Race
(B : BONUS with type t = Abilities.t) : PLAYABLE = struct
type t = {name : string ; abilities : Abilities.t}
let name character = character.name
let make name = {name ; abilities = Abilities.init()}
let bonus = Abilities.{
strength = B.value.strength
; dexterity = B.value.dexterity
; constitution = B.value.constitution
; intelligence = B.value.intelligence
; wisdom = B.value.wisdom
; charisma = B.value.charisma
}
let abilities character = Abilities.{
strength = character.abilities.strength + bonus.strength
; dexterity = character.abilities.dexterity + bonus.dexterity
; constitution = character.abilities.constitution + bonus.constitution
; intelligence = character.abilities.intelligence + bonus.intelligence
; wisdom = character.abilities.wisdom + bonus.wisdom
; charisma = character.abilities.charisma + bonus.charisma
}
end
module Dwarf = Race (val bonus Abilities.{
no_bonus with constitution = 2
})
module Elf = Race (val bonus Abilities.{
no_bonus with dexterity = 2
})
module Halfling = Race (val bonus Abilities.{
no_bonus with dexterity = 2
})
module Tiefling = Race (val bonus Abilities.{
no_bonus with charisma = 2 ; intelligence = 1
})
module HalfOrc = Race (val bonus Abilities.{
no_bonus with strength = 2
})
(* We can add new race with ease. Humans have +1 for all abilities *)
module Human = Race (val bonus Abilities.{
strength = 1
; dexterity = 1
; constitution = 1
; intelligence = 1
; wisdom = 1
; charisma = 1
})
바인
모든 유저는 서로 다른 종족의 배역을 맡을 수 있다.어떻게 모델링 팀을 만듭니까?
홀의 동료들
The companions is a book from R.A. Salvatore a novelist who has written many novels set in Faerûn
우리는 우리 동료들을 위해 가치를 창조할 수 있다.
let catti = Human.make "Catti-brie"
let regis = Halfling.make "Regis"
let brenor = Dwarf.make "Bruenor Battlehammer"
let wulfgar = Human.make "Wulfgar"
let drizzt = Elf.make "Drizzt Do'Urden"
우리가 동료를 만들면:❌ let companions = [catti; regis; bruenor; wulfgar; drizzt]
오류: 이 표현식의 유형은 HalfLing입니다.t그런데 형식적인 표현식이 있어야 돼요.인간.t
기억해라
list
의 유형은 type 'a t = 'a list
이고 추리기는 'a = Human.t
이다. 왜냐하면 이것은 우리의 목록 catti
의 첫 번째 요소의 유형이지만 regis
의 유형은 Halfling.t
이다.우리는 어떻게 해야만 컴파일러를 도울 수 있습니까?유형 매개 변수는 특정 유형이어야 합니다.
(* won't compile PLAYABLE is a module type *)
❌ type team = PLAYABLE.t list
(* won't compile RACE is a functor
** aka a function from module to module *)
❌ type team = RACE.t list
실제로 너무 복잡한 것은 없다. 주요한 것은 OCAml 목록이 단일한 것이기 때문에 우리는 독특한 유형이 필요하다. 그 종족이 무엇이든지 하나의 역할을 대표할 수 있다.type buddy =
| Dwarf of Dwarf.t
| Elf of Elf.t
| Halfling of Halfling.t
| Tiefling of Tiefling.t
| HalfOrc of HalfOrc.t
| Human of Human.t
let companions = [Human catti; Halfling regis; Dwarf bruenor; Human wulfgar; Elf drizzt]
하지만 파울린에는 다른 종족과 변종이 많다.예를 들어 최즈트는 정령이 아니라 어둠의 정령이었다.라이브러리를 쉽게 확장할 수 있도록 다중 변형을 사용하는 것이 좋습니다. 왜냐하면 우리는 아직 진정한 문자 생성기의 초기 단계에 있기 때문입니다.let companions_final =
[`Human catti; `Halfling regis; `Dwarf bruenor; `Human wulfgar; `Elf drizzt]
누구 타입일까요?val companions_final :
[> `Dwarf of Dwarf.t
| `Elf of Elf.t
| `Halfling of Halfling.t
| `Human of Human.t ]
list =
[`Human <abstr>; `Halfling <abstr>; `Dwarf <abstr>; `Human <abstr>;
`Elf <abstr>]
가져가다
1-OCAml은 다음을 추상화합니다.
Reference
이 문제에 관하여(지하성과 용과 편지), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/oteku/dungeon-dragons-fonctors-5aka텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)