2009-10-29 6 views
1

나는 프로젝트에서이 같은 코드의 조각을 가지고 있고 그것이 기능적인 방법으로 기록되지 있어 실현 :다음 fsharp 코드를 작성하는 것이 더 나은 (더 기능적인 방식입니까?)?

let data = Array.zeroCreate(3 + (int)firmwareVersions.Count * 27) 
data.[0] <- 0x09uy        //drcode 
data.[1..2] <- firmwareVersionBytes    //Number of firmware versions 



let mutable index = 0 
let loops = firmwareVersions.Count - 1 
for i = 0 to loops do 
    let nameBytes = ASCIIEncoding.ASCII.GetBytes(firmwareVersions.[i].Name) 
    let timestampBytes = this.getTimeStampBytes firmwareVersions.[i].Timestamp 
    let sizeBytes = BitConverter.GetBytes(firmwareVersions.[i].Size) |> Array.rev 

    data.[index + 3 .. index + 10] <- nameBytes 
    data.[index + 11 .. index + 24] <- timestampBytes 
    data.[index + 25 .. index + 28] <- sizeBytes 
    data.[index + 29] <- firmwareVersions.[i].Status 
    index <- index + 27 

firmwareVersions는 CSHARP 라이브러리의 일부 목록입니다. 바이트 배열을 으로 변환하는 방법에 대한 지식이 있습니다 (가지고 있으면 안됩니다). 나는 위의 코드는 매우 비 작동 실현, 그래서 나는 이런 식으로 변경 을 시도 :

let headerData = Array.zeroCreate(3) 
headerData.[0] <- 0x09uy 
headerData.[1..2] <- firmwareVersionBytes 

let getFirmwareVersionBytes (firmware : FirmwareVersion) = 
    let nameBytes = ASCIIEncoding.ASCII.GetBytes(firmware.Name) 
    let timestampBytes = this.getTimeStampBytes firmware.Timestamp 
    let sizeBytes = BitConverter.GetBytes(firmware.Size) |> Array.rev 
    Array.concat [nameBytes; timestampBytes; sizeBytes] 

let data = 
    firmwareVersions.ToArray() 
    |> Array.map (fun f -> getFirmwareVersionBytes f) 
    |> Array.reduce (fun acc b -> Array.concat [acc; b]) 

let fullData = Array.concat [headerData;data] 

를이 코드를 작성하는 더 나은 (더 많은 기능) 방법 경우 그래서 지금 내가 궁금하네요. 그렇다면 ... 개선해야하는 이유와 개선점은 무엇입니까? 그렇지 않은 경우 왜 대신 무엇을해야합니까?

의견, 의견, 비고?

업데이트

가 그냥 몇 가지 정보를 추가하고 싶었 감사드립니다. 이것은 바이너리 통신 프로토콜에 대한 데이터를 처리하는 일부 라이브러리의 일부입니다. 코드의 첫 번째 버전에서 볼 수있는 유일한 단점은 다른 언어로 프로토콜을 구현하는 사람들 (우리 상황에서도 마찬가지로 )은 각 부분이 차지하는 바이트 수를 더 잘 이해할 수 있다는 것입니다. 정확히 어디에 그들은 바이트 스트림에 위치하고 있습니다 ... 그냥 발언. (모두가 영어를 이해하지만, 모든 파트너는 코드를 읽을 수 있습니다.)

답변

1

저는 색인 생성이 문제의 중요한 부분 인 오프셋의 더 나은 그림을 제공하기 때문에 첫 번째 버전을 더 좋아합니다. 명령형 코드는 바이트 오프셋을 눈에 잘 띄게 나타내며 파트너가 문서를 읽을 수 없거나 읽을 수없는 경우 중요 할 수 있습니다. 기능 코드는 함께 고정 된 구조를 강조합니다. 바이트 오프셋이 설명서에 언급 될만큼 중요하지 않으면 OK입니다.

색인 생성은 일반적으로 실수로 복잡하므로이 경우 피해야합니다. 예를 들어 첫 번째 버전의 루프는 for i = 0 to loops 대신 for firmwareVersion in firmwareVersion이 될 수 있습니다.

또한 Brian에 따르면 오프셋에 상수를 사용하면 명령형 버전을 훨씬 쉽게 읽을 수 있습니다.당신이 바이트의 위치를 ​​전달하려면

let fullData = 
    [|yield! [0x09uy; firmwareVersionBytes; firmwareVersionBytes] 
    for firmware in firmwareVersions do 
     yield! ASCIIEncoding.ASCII.GetBytes(firmware.Name) 
     yield! this.getTimeStampBytes firmware.Timestamp 
     yield! BitConverter.GetBytes(firmware.Size) |> Array.rev|] 

, 나는이 말에 의견에 넣어 것 :

+0

내 경우에는 우리 동료들이 문서를 걱정하지 않아도 오프셋을 볼 수있는 것이 더 중요하다. Brian이 오버 헤드에 대해 말한 것입니다 .... 나는 함수 적 프로그래밍이 오버 헤드를 야기하는지 그리고 함수 적 프로그래밍을 사용하기 위해 메모리/퍼포먼스를 포기할 지 궁금합니다. – TimothyP

+0

함수 프로그래밍으로 인해 프로그래밍이 편하다. – TimothyP

+1

예, 가비지가 종종 기능 프로그램의 성능 문제의 원인입니다. 당신은 영리하거나 낮은 수준의 파괴적인 기능을 사용할 수 있습니다. 첫 번째 접근법에 대해서는 Purely Functional Data Structures (http://www.eecs.usma.edu/webs/people/okasaki/pubs.html#cup98)를 살펴보십시오. 두 번째 접근법에서는 고정 된 양의 메모리를 미리 할당하고 인수를 채우는 Array.concat_destructive를 상상할 수 있습니다. 또는 컴파일러에서 더러운 작업을 수행 할 수도 있습니다. Real World Haskell (http://book.realworldhaskell.org/read/profiling-and-optimization.html)의 제 25 장을 참조하십시오. –

1

얼마나 자주 코드가 실행됩니까?

'배열 연결'의 장점은 논리적 부분을보다 쉽게 ​​볼 수 있다는 것입니다. 단점은 많은 양의 가비지 (임시 배열 할당)를 생성하고 엄격한 루프에서 사용하는 경우 느려질 수도 있다는 것입니다.

또한 "Array.reduce (...)"는 "Array.concat"일 수 있습니다.

전반적으로 논리를보다 분명하게 보이도록 (예 : 명명 된 상수 HEADER_SIZE 등) 다른 방식으로 고려해보기는하지만 전체적으로 첫 번째 방법 (그냥 하나의 거대한 배열 만들기)을 선호합니다.

Google에서 논의하는 동안 몇 가지 주장을 추가하여 예를 들어 nameBytes는 예상 길이입니다.

+0

이 특정 요청이 에뮬레이터에 생성되면 코드가 실행됩니다 (이 코드는 현재 개발중인 하드웨어를 에뮬레이트하는 소프트웨어의 일부로, 테스트 엔지니어는이를 사용하여 클라이언트 소프트웨어를 테스트합니다). 그러나 많은 메시지가 있습니다 이와 같은 데이터를 생성하는 for 루프를 포함하는 프로토콜에서) – TimothyP

+0

이름의 크기는 FirmwareVersion 클래스에서 유효하며 항상 8 자로 확장됩니다. (우리가 정의하지 않은 프로토콜의 요구 사항) – TimothyP

2

나는 전체 프로그램은 짧은 너무 많이되기 때문에 모든 인라인 경사 할 것 각 라인.

+0

코드에는 주석이 필요하지 않습니다. .. 자명하다. 가독성을 선호한다 ... 더 많은 코드 라인을 필요로한다. – TimothyP