하스켈이 돌연변이를 전혀 제공하지 않는다는 공통된 신화입니다. 실제로 이것은 매우 특별한 종류의 돌연변이를 제공합니다. 평가되지 않은 것에서 평가 된 것까지 한 번 정확하게 변이 될 수 있습니다. 이 특별한 종류의 돌연변이를 이용하는 기술은 tying the knot입니다. 우리는 C++에서 같은 데이터 구조로 시작됩니다
data Vector -- held abstract
data Point = Point
{ position :: Vector
, v, w :: Double
, neighbors :: [Point]
}
지금, 우리가 할거야 누구의 Array Point
neighbors
가 같은 배열 내에서 다른 요소에 대한 포인터를 포함 구축이다. 다음 코드에서 Array
의 주요 기능은 척추 게으른 (요소가 너무 빨리 적용되지 않음) 빠른 임의 액세스가 있다는 점입니다. 원하는 경우 선호하는 대체 데이터 구조를 이러한 속성으로 대체 할 수 있습니다.
이웃 찾기 기능의 인터페이스에는 다양한 선택 항목이 있습니다. 구체성과 자신의 일을 간단하게하기 위해 나는 Vector
과 Vectors
의 목록을 가지고 이웃의 지수를주는 함수를 가지고 있다고 가정합니다.
findNeighbors :: Vector -> [Vector] -> [Int]
findNeighbors = undefined
는의도
computeV
및
computeW
장소에서 몇 가지 유형을 넣어 보자.nonce의 경우
position
및
neighbors
필드가
Point
이며,
v
또는
w
필드는 볼 수 없다는 내용의 비공식 계약서를
computeV
에 부탁합니다. 마찬가지로,
computeW
은
Point
의
w
필드를 볼 수도 있지만 너무 많은 체조가 없으면 유형 수준에서이를 적용 할 수 있지만 실제로는 건너 뜁니다.
computeV, computeW :: Point -> Double
(computeV, computeW) = undefined
이제 우리는 (라벨이 붙은) 인 - 메모리 그래프를 만들 준비가되었습니다.
buildGraph :: [Vector] -> Array Int Point
buildGraph vs = answer where
answer = listArray (0, length vs-1) [point pos | pos <- vs]
point pos = this where
this = Point
{ position = pos
, v = computeV this
, w = computeW this
, neighbors = map (answer!) (findNeighbors pos vs)
}
그리고 그게 사실입니다.
update :: [Vector] -> [Vector]
update = newPositions <=< elems . buildGraph
편집 : ... 설명 지금 당신은
newPositions :: Point -> [Vector]
newPositions = undefined
newPositions
그것을 건네 년대
Point
의 필드 중 하나를 검사하고, 함께 모든 기능을 넣어 완벽하게 무료
하여 쓸 수 있습니다 처음에는 "특별한 종류의 돌연변이"주석이 있습니다. 평가 중에는 다음과 같은 일들이 일어날 것이라고 w
필드에 요구합니다. computeW
은 v
필드를 강제합니다. computeV
은 강제로 neighbors
필드를 나타냅니다. neighbors
필드는 평가되지 않은 것으로부터 평가 된 것으로 변합니다. v
필드는 평가되지 않은 값에서 평가 된 값으로 변경됩니다. w
필드는 평가되지 않은 것으로부터 평가 된 것으로 변합니다. 마지막 세 단계는 C++ 알고리즘의 세 가지 돌연변이 단계와 매우 유사합니다!
두 번 편집 : 나는이 일을보고 싶다고 결심했다. 그래서 위에서 추상화 된 모든 것들을 더미 구현으로 인스턴스화했다. 나는 또한 내가 그것을 올바르게했다고 확신하지 못했기 때문에 그것이 단지 한 번만 평가하는 것을보고 싶었다! 그래서 나는 trace
전화를 던졌다.
import Control.Monad
import Data.Array
import Debug.Trace
announce s (Vector pos) = trace $ "computing " ++ s ++ " for position " ++ show pos
data Vector = Vector Double deriving Show
data Point = Point
{ position :: Vector
, v, w :: Double
, neighbors :: [Point]
}
findNeighbors :: Vector -> [Vector] -> [Int]
findNeighbors (Vector n) vs = [i | (i, Vector n') <- zip [0..] vs, abs (n - n') < 1]
computeV, computeW :: Point -> Double
computeV (Point pos _ _ neighbors) = sum [n | Point { position = Vector n } <- neighbors]
computeW (Point pos v _ neighbors) = sum [v | Point { v = v } <- neighbors]
buildGraph :: [Vector] -> Array Int Point
buildGraph vs = answer where
answer = listArray (0, length vs-1) [point pos | pos <- vs]
point pos = this where { this = Point
{ position = announce "position" pos $ pos
, v = announce "v" pos $ computeV this
, w = announce "w" pos $ computeW this
, neighbors = announce "neighbors" pos $ map (answer!) (findNeighbors pos vs)
} }
newPositions :: Point -> [Vector]
newPositions (Point { position = Vector n, v = v, w = w }) = [Vector (n*v), Vector w]
update :: [Vector] -> [Vector]
update = newPositions <=< elems . buildGraph
과 ghci에서 실행 : 당신이 볼 수 있듯이
*Main> length . show . update . map Vector $ [0, 0.25, 0.75, 1.25, 35]
computing position for position 0.0
computing v for position 0.0
computing neighbors for position 0.0
computing position for position 0.25
computing position for position 0.75
computing w for position 0.0
computing v for position 0.25
computing neighbors for position 0.25
computing v for position 0.75
computing neighbors for position 0.75
computing position for position 1.25
computing w for position 0.25
computing w for position 0.75
computing v for position 1.25
computing neighbors for position 1.25
computing w for position 1.25
computing position for position 35.0
computing v for position 35.0
computing neighbors for position 35.0
computing w for position 35.0
123
, 각 필드는 대부분 한 번 각 위치에서 계산 다음은 전체 파일입니다.
@ChrisTaylor가 준 답변을 좋아합니다. 또한 배열에 저장된 데이터의 실제 돌연변이를 필요로하는 알고리즘의 경우'ST' 모나드 ('vectors' 패키지에서)에 가변적 인 벡터를 사용했습니다. –