anchor.diff:            PeriodTimeout = periodTimeout }
   
       // update : MemberList -> Node -> Status -> MemberList
  -    let update memberList node = function
  -        | Alive i -> alive memberList node i
  -        | Suspect i -> suspect memberList node i
  -        | Dead i -> dead memberList node i
  -
  -module FailureDetection =
  -    // ping : SeqNumber -> Async<bool>
  -    // pingRequest : SeqNumber -> Node -> Async<bool>
  -    // ack : Node -> SeqNumber -> unit
  +    let update node status memberList =
  +        match status with
  +        | Alive i -> alive node i memberList
  +        | Suspect i -> suspect node i memberList
  +        | Dead i -> dead node i memberList
  +
  +type FailureDetector =
  +    private { Timeout : TimeSpan
  +              AsyncSendMessage : Node -> SwimMessage -> Async<unit>
  +              AsyncReceiveMessageFor : (Node -> SwimMessage -> bool) -> TimeSpan -> Async<SwimMessage option> }
  +
  +[<RequireQualifiedAccess; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
  +module FailureDetector =
  +    // ackFilter : Node -> SeqNumber -> Node -> SwimMessage -> bool
  +    let private ackFilter node seqNr = fun _ -> 
  +        function Ack(s, n) -> seqNr = s && node = n | _ -> false
  +
  +    // sendMessage : FailureDetector -> Node -> SwimMessage
  +    let private sendMessage detector node message = async {
  +        do! detector.AsyncSendMessage node message
  +        return None
  +    }
  +
  +    // make : TimeSpan -> (Node -> SwimMessage -> Async<unit>) -> ((Node -> SwimMessage -> bool) -> TimeSpan -> Async<SwimMessage option>) -> FailureDetector
  +    let make timeout asyncSendMessage asyncReceiveMessageFor =
  +        { Timeout = timeout
  +          AsyncSendMessage = asyncSendMessage
  +          AsyncReceiveMessageFor = asyncReceiveMessageFor }
  +
  +    // ping : SeqNumber -> Node -> FailureDetector -> Async<bool>
  +    let ping seqNr node detector = async {
  +        let! results =
  +            [ detector.AsyncReceiveMessageFor (ackFilter node seqNr) detector.Timeout
  +              Ping seqNr |> sendMessage detector node ]
  +            |> Async.Parallel
  +
  +        return Array.head results |> Option.isSome
  +    }
  +
  +    // pingRequest : SeqNumber -> Node -> Node list -> FailureDetector -> Async<bool>
  +    let pingRequest seqNr node nodes detector = async {
  +        let messages = nodes |> List.map (fun n -> PingRequest(seqNr, node) |> sendMessage detector n)
  +
  +        let! results =
  +            detector.AsyncReceiveMessageFor (ackFilter node seqNr) detector.Timeout :: messages
  +            |> Async.Parallel
  +
  +        return Array.head results |> Option.isSome
  +    }
  +
  +    // ack : SeqNumber -> Node -> Node -> FailureDetector -> unit
  +    let ack seqNr node replyNode detector = 
  +        Ack(seqNr, node) |> detector.AsyncSendMessage replyNode
  +
   
   module Swim =
       type Config =
  
positive.code:           PingTimeout : TimeSpan
            PingRequestGroupSize : int
            SuspectTimeout : TimeSpan }
  
negative.code:         { memberList with Members = members' }
  
      // stillAlive : MemberList -> IncarnationNumber -> MemberList
      let private stillAlive incarnation memberList =
          let { Local = local
                Incarnation = currentIncarnation } = memberList
          let incarnation' =  if currentIncarnation > incarnation then currentIncarnation
  