2009-11-14 3 views
0

저는 스칼라에서 함수가 있고 JavaScript에서 같은 함수이지만 기능적인 스타일이라고 생각하지 않습니다.함수형 프로그래밍 스타일로 sierpinski 삼각형 생성기를 만들려고 시도합니다.

def drawSurroundingTriangles(startx : Double, starty : Double, width : Double) { 
    var newwidth = width/2; 
    var newstartx = startx + newwidth/2; 
    var newstarty = starty - newwidth; 
    drawTriangle(newstartx, newstarty, newwidth); 
    drawTriangle(newstartx - newwidth, starty + newwidth, newwidth); 
    drawTriangle(newstartx + newwidth, starty + newwidth, newwidth); 
    if(newwidth < 6) 
     return; 
    drawSurroundingTriangles(newstartx, newstarty, newwidth); 
    drawSurroundingTriangles(newstartx - newwidth, starty + newwidth, newwidth); 
    drawSurroundingTriangles(newstartx + newwidth, starty + newwidth, newwidth); 
} 

내 희망이 오히려 재귀하는 것보다, 반복자가 될 것입니다, 그래서 다음 반복을 받고 유지할 수 있습니다, 내 프로그램은 처음에 외부 삼각형을 만들고 그래서, 다음 단계를 인쇄 할 것이다, 그런 다음 첫 번째 내부 삼각형을 그립니다. 반복자로 만들면 매번 색상을 변경하여 다음 반복 작업을 수행하기 위해 키를 누를 때까지 기다릴 수 있습니다.

  1. 3 개 삼각형 중앙 삼각형
  2. 양쪽 하나 그리기 9 개 삼각형을 그리 하나 : 각각의 반복에 있도록 그 후

    , 그것은,이 함수는 것 루프에 도달 각 측에 이전 반복에서 3 개의 삼각형 중 .

  3. 27 개 삼각형

...

UPDATE 그리기 :

미안 해요, 난 잊었 물음표, 그래서 질문을 참조하기 어렵다.

기본적으로 재귀 함수에서 필요에 따라 호출 할 수있는 함수로 변경하고 다음 반복을 그립니다. 어떻게하면됩니까?

업데이트 2 :

나는 작동하는 솔루션을 가지고,하지만 난 몰라 솔루션은 더 인 내 또는이 질문에 대답 한 :

def drawSurroundingTriangles(indexlist : List[(Double, Double, Double)]) : List[(Double, Double, Double)] = { 
    var mylist = ListBuffer[(Double, Double, Double)]() 
    indexlist.foreach{ 
     case (startx, starty, width) => { mylist ++ drawSingleTriangle(startx, starty, width) } } 

    mylist.toList; 
} 

def drawSingleTriangle(startx : Double, starty : Double, width : Double) : List[(Double, Double, Double)] = { 
    val newwidth = width/2; 
    val newstartx = startx + newwidth/2; 
    val newstarty = starty - newwidth; 
    var list = List((newstartx, newstarty, newwidth), 
      ((newstartx - newwidth, starty + newwidth, newwidth)), 
      (newstartx + newwidth, starty + newwidth, newwidth)); 
    list.foreach{ case (nstartx, nstarty, nwidth) => drawTriangle(nstartx, nstarty, nwidth)} 
    list; 
} 
+0

그럼 궁금한 점은 무엇입니까? – sanity

+0

이 함수를 반복자로 반복 할 수 있도록이 함수를 어떻게 변경합니까? –

+7

"함수 프로그래밍 스타일에서 ..."... "재귀가 없음". 그런데 "나는 관용적 인 OOP 스타일로 쓰길 원하지만 어떤 수업도 듣고 싶지 않다"고 말하는 것이 아닌가? – Juliet

답변

2

함수가 쌍을 반환하는지 확인하십시오. 왼쪽 절반은 현재 반복에 대한 삼각형을 포함합니다. 내가 시도하지했습니다

type Triangle = (Double, Double, Double) 

def fractal(width : Double): Stream[List[Triangle]] = { 
    val w2 = width/2 
    def surrounding(t: Triangle) = match t case (startx, starty, width) => { 
    val w = width/2 
    val x = startx + w/2 
    val y = starty - w 
    List((x, y, w), 
     (x - w, starty + w, w), 
     (x + w, starty + w, w)) 
    } 
    def s(tris: List[Triangle]): Stream[List[Triangle]] = 
    Stream.cons(tris, s(tris.flatMap(surrounding(_)))) 
    s(List((w2/2, w2, w2))) 
} 

: 오른쪽 절반이 여기에 당신이 당신의 솔루션을 재 작성하는 방법의 다음 반복과 기능에 삼각형을 포함하는 쌍을 반환하는 함수 ...

편집을 포함 그러나이 효과에 아주 많은 것은 여러분에게 반복의 흐름을 줄 것이고, 각각의 반복은 삼각형의 목록이 될 것입니다. 반복을 그리려면 스트림에서 그냥 튀어 나오고 drawTriangle을 호출하면됩니다.

스타일 팁 : 피하십시오 foreach. 탭 대신 2 또는 3 개의 공백을 사용하십시오. 간결한 이름을 사용하면 어디서나 빠져 나갈 수 있으므로 코드를 사용하여 구조를 더 쉽게 검사 할 수 있습니다. 세미콜론은 불필요한 잡음입니다.

+0

재미있는 아이디어입니다. 현재 솔루션보다 큰 아키텍처 개선이 될 것 같아서 시도해 보겠습니다. –

+1

이것은 잘 알려진 "패턴"이며 심지어 이름이 있습니다. 아이덴터티 펑서 (Identity Functor)의 동족적 인 연합입니다. 구현은 표준 라이브러리에서'scala.Stream' 클래스로 제공됩니다. – Apocalisp

+0

내가 뭘하고 싶은지, 또 다른 질문을하는 것은 부분 함수가되도록하는 것입니다. 그래서 다음 반복 계산을위한 함수를 설정할 수 있습니다. 그리고 나는 현재 삼각형 정보를 계속 전달할 필요가 있습니다. 시각. –

1

스트림은 잠재적으로 제한되지 않은 시퀀스의 지연 계산을 캡슐화합니다. 최소 요구 사항에 부합하거나 또는 놀랄만큼 까다로워 질 수 있지만 요구 사항을 충족시켜야합니다. Scaladoc을 점검하고, 블로그를 찾고, 2.7 라이브러리에서 구현의 효율성뿐만 아니라 게으르다는 것을 충분히 이해하지 못하면서 그 사용을 둘러싸고있는 많은 불행에 대한 스칼라 메일 링리스트 아카이브를 검색하십시오. ..

... 너무 모호 할 수 있지만 한 번을 사용했습니다 반면, 좀 더 구체적으로 시도 할 자격이 생각하지 않습니다 죄송합니다

랜달 슐츠

1

나는 코드를 생각한다 아래는 코드를 충실하게 재현 한 것입니다. Iterator, 을 만든 다음 다른 반복기처럼 반복하면됩니다.

case class Triangle(startx: Double, starty: Double, width: Double) 

class drawSurroundingTrianglesIterator(original: Triangle) extends Iterator[Unit] { 
    private case class Iteration(old: Triangle, `new`: Triangle) 
    private var iteration = List(newIteration(original)) 

    def hasNext = ! iteration.isEmpty 
    def next = { 
    iteration = iteration flatMap variants map newIteration 
    iteration map (_.old) foreach draw 
    iteration = iteration filter (_.`new`.width > 5) 
    } 

    private def newIteration(triangle: Triangle) = { 
    import triangle._ 
    Iteration(triangle, Triangle(startx + width/4, starty - width/2, width/2)) 
    } 

    private def variants(iteration: Iteration) = { 
    import iteration._ 
    import `new`._ 
    List(Triangle(startx, starty, width), 
     Triangle(startx - width, old.starty + width, width), 
     Triangle(startx + width, old.starty + width, width)) 
    } 

    private def draw(triangle: Triangle) = { 
    import triangle._ 
    drawTriangle(startx, starty, width) 
    } 
} 

사용 예 : 분명히에서 var와 같이

scala> new drawSurroundingTrianglesIterator(Triangle(100, 100, 40)) 
res1: drawSurroundingTrianglesIterator = non-empty iterator 

scala> res1 foreach (x => x) 
Drawing 110,000000, 80,000000, 20,000000 
Drawing 90,000000, 120,000000, 20,000000 
Drawing 130,000000, 120,000000, 20,000000 
Drawing 115,000000, 70,000000, 10,000000 
Drawing 105,000000, 90,000000, 10,000000 
Drawing 125,000000, 90,000000, 10,000000 
Drawing 95,000000, 110,000000, 10,000000 
Drawing 85,000000, 130,000000, 10,000000 
Drawing 105,000000, 130,000000, 10,000000 
Drawing 135,000000, 110,000000, 10,000000 
Drawing 125,000000, 130,000000, 10,000000 
Drawing 145,000000, 130,000000, 10,000000 

이제이 완전히 비 기능입니다.당신이 반복적으로 그것을 할 싶어하지만 기능적으로, 당신은 무엇 next와 유사한 함수에 인수로 "상태"를 통과해야하는 경우하고있다 : 첫 번째를 생성 할 수 있도록

case class Triangle(startx: Double, starty: Double, width: Double) 
case class Iteration(old: Triangle, `new`: Triangle) 

object TriangleIterator { 
    def iterate(from: List[Iteration]) = { 
    val iteration = from flatMap variants map newIteration 
    iteration map (_.old) foreach draw 
    iteration filter (_.`new`.width > 5) 
    } 

    def newIteration(triangle: Triangle) = { 
    import triangle._ 
    Iteration(triangle, Triangle(startx + width/4, starty - width/2, width/2)) 
    } 

    private def variants(iteration: Iteration) = { 
    import iteration._ 
    import `new`._ 
    List(Triangle(startx, starty, width), 
     Triangle(startx - width, old.starty + width, width), 
     Triangle(startx + width, old.starty + width, width)) 
    } 

    private def draw(triangle: Triangle) = { 
    import triangle._ 
    drawTriangle(startx, starty, width) 
    } 
} 

을이 경우에 나는 newIteration 공개 하나. 다음은 사용 예입니다.

scala> List(TriangleIterator.newIteration(Triangle(100, 100, 50))) 
res0: List[Iteration] = List(Iteration(Triangle(100.0,100.0,50.0),Triangle(112.5,75.0,25.0))) 

scala> TriangleIterator.iterate(res0) 
Drawing 112,500000, 75,000000, 25,000000 
Drawing 87,500000, 125,000000, 25,000000 
Drawing 137,500000, 125,000000, 25,000000 
res1: List[Iteration] = List(Iteration(Triangle(112.5,75.0,25.0),Triangle(118.75,62.5,12.5)), Iteration(Triangle(87.5,12 
5.0,25.0),Triangle(93.75,112.5,12.5)), Iteration(Triangle(137.5,125.0,25.0),Triangle(143.75,112.5,12.5))) 

scala> TriangleIterator.iterate(res1) 
Drawing 118,750000, 62,500000, 12,500000 
Drawing 106,250000, 87,500000, 12,500000 
Drawing 131,250000, 87,500000, 12,500000 
Drawing 93,750000, 112,500000, 12,500000 
Drawing 81,250000, 137,500000, 12,500000 
Drawing 106,250000, 137,500000, 12,500000 
Drawing 143,750000, 112,500000, 12,500000 
Drawing 131,250000, 137,500000, 12,500000 
Drawing 156,250000, 137,500000, 12,500000 
res2: List[Iteration] = List(Iteration(Triangle(118.75,62.5,12.5),Triangle(121.875,56.25,6.25)), Iteration(Triangle(106. 
25,87.5,12.5),Triangle(109.375,81.25,6.25)), Iteration(Triangle(131.25,87.5,12.5),Triangle(134.375,81.25,6.25)), Iterati 
on(Triangle(93.75,112.5,12.5),Triangle(96.875,106.25,6.25)), Iteration(Triangle(81.25,137.5,12.5),Triangle(84.375,131.25 
,6.25)), Iteration(Triangle(106.25,137.5,12.5),Triangle(109.375,131.25,6.25)), Iteration(Triangle(143.75,112.5,12.5),Tri 
angle(146.875,106.25,6.25)), Iteration(Triangle(131.25,137.5,12.5),Triangle(134.375,131.25,6.25)), Iteration(Triangle(15 
6.25,137.5,12.5),Triangle(159.375,131.25,6.25))) 

scala> TriangleIterator.iterate(res2) 
Drawing 121,875000, 56,250000, 6,250000 
Drawing 115,625000, 68,750000, 6,250000 
Drawing 128,125000, 68,750000, 6,250000 
Drawing 109,375000, 81,250000, 6,250000 
Drawing 103,125000, 93,750000, 6,250000 
Drawing 115,625000, 93,750000, 6,250000 
Drawing 134,375000, 81,250000, 6,250000 
Drawing 128,125000, 93,750000, 6,250000 
Drawing 140,625000, 93,750000, 6,250000 
Drawing 96,875000, 106,250000, 6,250000 
Drawing 90,625000, 118,750000, 6,250000 
Drawing 103,125000, 118,750000, 6,250000 
Drawing 84,375000, 131,250000, 6,250000 
Drawing 78,125000, 143,750000, 6,250000 
Drawing 90,625000, 143,750000, 6,250000 
Drawing 109,375000, 131,250000, 6,250000 
Drawing 103,125000, 143,750000, 6,250000 
Drawing 115,625000, 143,750000, 6,250000 
Drawing 146,875000, 106,250000, 6,250000 
Drawing 140,625000, 118,750000, 6,250000 
Drawing 153,125000, 118,750000, 6,250000 
Drawing 134,375000, 131,250000, 6,250000 
Drawing 128,125000, 143,750000, 6,250000 
Drawing 140,625000, 143,750000, 6,250000 
Drawing 159,375000, 131,250000, 6,250000 
Drawing 153,125000, 143,750000, 6,250000 
Drawing 165,625000, 143,750000, 6,250000 
res3: List[Iteration] = List() 
+0

고맙습니다. 오늘 나중에 다시 시도하겠습니다. List <(Double, Double, Double))이 작동하는지, 튜플이 (startx, starty, width) 어디에서 작동하는지 보려고 실험하고 있지만 너는 더 단순 해 보입니다. –

0

내가 여기 온 최종 답이 있지만, Aposcalisp의 답변을 제외하고는 카레 기능을 전혀 생각하지 못했습니다.

이 기능을 개선하기 위해 특성을 사용해야하는지는 잘 모르겠지만이 방법을 반복하는 가장 좋은 방법이라고 생각합니다.

def drawFractal(width : Double) { 
    val mywidth = width/2; 
    val drawSurroundingTriangles = drawSurroundingTrianglesComplete((startx, starty, width) => { 
      val newwidth = width/2; 
      val newstartx = startx + newwidth/2; 
      val newstarty = starty - newwidth; 
      var list = List((newstartx, newstarty, newwidth), 
        ((newstartx - newwidth, starty + newwidth, newwidth)), 
        (newstartx + newwidth, starty + newwidth, newwidth)); 
      list.foreach{ case (nstartx, nstarty, nwidth) => drawTriangle(nstartx, nstarty, nwidth)} 
      list; 
    })_ 

    var mylist = drawSurroundingTriangles(List((mywidth/2, mywidth, mywidth))); 
    mylist.foreach{ case (startx, starty, width) => print ("[" + startx + "," + starty + "," + width + "]\n")} 
    print("\n"); 
    mylist = drawSurroundingTriangles(mylist); 
    mylist.foreach{ case (startx, starty, width) => print ("[" + startx + "," + starty + "," + width + "]\n")} 
} 
def drawSurroundingTrianglesComplete(myfunc : (Double, Double, Double) => List[(Double, Double, Double)]) 
(indexlist : List[(Double, Double, Double)]) : 
    List[(Double, Double, Double)] = { 
    var mylist = ListBuffer[(Double, Double, Double)]() 
    indexlist.foreach{ 
     case (startx, starty, width) => { mylist ++= myfunc(startx, starty, width) } } 
    mylist.toList; 
} 
관련 문제