nim i multimethods

bmaxa

Buduća legenda
Poruka
42.102
Verovatno ste culi za multhimethods, double dispatch ili visitor pattern?
Radi se o tome da virtualne funkcije metodi, dispatchuju samo na jednom
objektu u skoro svim jezicima. ova dva gorepomenuta patterna simulira
multiple dispatch u takvim jezicima kao sto su Java, C++, C#...
Dakle, nim podrzava dispatch vituelnih funkcija nad vise tipova
objekata, zato mi je interesantan :P
Evo primera, koji sam ranije navodio, pancake sort u nimu :P
Kod:
import strutils,algorithm

type
  State = ref object of RootObj
  Move = ref object of RootObj
  Domain = ref object of RootObj
  Search = object
    solution: seq[State]
    treshold: int
    verbose: bool
# state methods
method `$`(s:State):string {.base.} =
  "default State"
method copyState(s:State):State {.base.}=
  echo "default copyState"
# Domain methods
method makeTestState(d:Domain):State {.base.}=
  echo "default makeTestState"
method heuristic(d:Domain,s:State):int {.base.}=
  echo "default heuristic"
method bf(d:Domain,s:State):int {.base.} =
  echo "default bf"
method getMove(d:Domain,m:int):Move {.base.} =
  echo "default getMove"
method makeMove(d:Domain,s:State,m:Move) {.base.} =
  echo "default makeMove"
method unmakeMove(d:Domain,s:State,m:Move) {.base.} =
  echo "default unmakeMove"
# Search procs
proc df(search:var Search,domain:Domain,state:State,depth:int):bool =
  if depth == 0 : echo "Treshold ",search.treshold
  if domain.heuristic(state) == 0 :
    search.solution[depth] = state.copyState
    return true
  if depth == search.treshold: return false
  if search.verbose : echo "".indent(4*depth," "),state
  for i in 0..<domain.bf(state) :
    let move = domain.getMove(i)
    domain.makeMove(state,move)
    if search.df(domain,state,depth+1) :
      domain.unmakeMove(state,move)
      search.solution[depth]=state.copyState
      return true
    domain.unmakeMove(state,move)
  false
proc id(search:var Search,domain:Domain,start:State) =
  search.treshold=0
  while true:
    search.solution = newSeq[State](search.treshold+1)
    if search.df(domain,start,0): break
    search.treshold+=1
  for i in search.solution :
    echo i
#concrete implementations
type
  PancakeState = ref object of State
    state: seq[int]
  PancakeMove = ref object of Move
    i: int
  Pancake = ref object of Domain
#PancakeState methods
method `$`(s:PancakeState):string =
  result = "["
  var first = true
  for i in s.state :
    if not first : result &= " "
    result &= $i
    first = false
  result &= "]"
method copyState(s:PancakeState):State =
  var state : PancakeState
  new(state)
  state.state = s.state
  result = state
#Pancake methods
method makeTestState(p:Pancake):State =
  var state:PancakeState
  new(state)
  state.state = @[0, 5, 4, 7, 2, 6, 1, 3]
  result = state
method heuristic(p:Pancake,ps:PancakeState):int =
  result = 0
  for i in 1..<ps.state.len :
    if abs(ps.state[i]-ps.state[i-1])>1 :
      result+=1
  if ps.state[0] != 0 : result+=1
method bf(p:Pancake,ps:PancakeState):int =
  result = ps.state.len-1
method getMove(p:Pancake,i:int):Move =
  var move : PancakeMove
  new (move)
  move.i = i+2
  result = move
method makeMove(p:Pancake,ps:PancakeState,pm:PancakeMove)=
  reverse(ps.state,0,pm.i-1)
method unmakeMove(p:Pancake,s:PancakeState,m:PancakeMove)=
  makeMove(p,s,m)
#main code
let domain = new(Pancake)
var search = Search()
echo domain.makeTestState()
search.verbose = false
let s = domain.makeTestState()
search.id(domain,s)
primeticete da make/unmake move dispatchuju po 3 objekta.
U klasicnim OO jezicima bi morao da se uradi dynamic cast
u zeljeni tip, a dispatch bi isao samo na prvom parametru...
 

Top