2012-01-22 5 views
2

하스켈을 호출하는 C 함수가 있습니다. C 함수는 Haskell 데이터 유형의 StablePtr을 전달하며 Haskell 코드는 그 값 중 일부를 변경해야합니다. 이 작업을 수행하는 효율적인 방법은 무엇입니까? 예를 들어,이 하스켈 + StablePtr

foreign export ccall editChar :: StablePtr MyObject -> CInt -> CChar -> IO() 

data MyObject = Obj String 

editChar :: StablePtr MyObject -> CInt -> CChar -> IO() 
editChar cMyObjectPtr index newChar = do 
    -- Code goes here 

어떻게

이 editChar이 newChar에인덱스에서 숯불을 설정하기 위해 가능한 한 효율적이고 Haskelly로 구현 될 것이다 다음 사항을 고려? 결국 돌연변이 된 객체는 메모리가 크고 많은 하위 컴포넌트를 가지므로 editChar의 결과로 새로운 객체를 반환하는 것은 문제가되지 않습니다.

답변

4

안에 Char을 돌연변이시킬 수 없습니다. 실제로 StablePtr의 내용을 전혀 변경할 수 없습니다. StablePtr을 참조하여 MyObject을 다시 가져 오면됩니다.

당신이

newtype MyObject = Obj (IORef String) 

(또는 MVar 대신 IORef)를 정의 경우에 당신은 보통의 방법을 통해 그것을 변이 할 수 있습니다.

메모리 소비가 염려되는 부분이 있다면 String은 적합하지 않습니다. 5 machine words per character을 사용합니다. 그러나 "새로운 값을 반환하는"오버 헤드는 생각만큼 높지 않을 수 있습니다. 공유 덕분에 을 String에 붙이면 전체 문자열이 복사되지 않고 "이전"참조가 다시 사용됩니다 . Seq과 같은 트리 구조를 사용하면 이러한 이점을 통해 요소를 대체 할 수 있습니다.

그러나 돌연변이가 많은 경우에는 vector을 사용할 수 있습니다.

물론, String이 (마지막 단락에서 암시 하듯이) 예제 일 경우이 조언이 반드시 적용되는 것은 아닙니다. 하지만

data Huge = Huge { giganticPart :: Gigantic, smallPart :: Int } 

이있는 경우 다음 myHuge { smallPart = 42 } 전체 Gigantic을 복사하지 않을, 그리고 Gigantic 적절한 트리 구조 인 경우, 당신은 모든 일을 복사하지 않고 그것을 수정 사항을 수행 할 수 있습니다. 이것은 순전히 기능적이며 지속적인 데이터 구조의 핵심 아이디어이며 Haskell의 가장 중요한 장점 중 하나입니다.