{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
module Ouroboros.Network.Protocol.Handshake.Client
( handshakeClientPeer
, decodeQueryResult
, encodeVersions
, acceptOrRefuse
) where
import Data.Map (Map)
import Data.Map qualified as Map
import Data.Text (Text)
import Codec.CBOR.Term qualified as CBOR
import Network.TypedProtocol.Peer.Client
import Ouroboros.Network.Protocol.Handshake.Codec
import Ouroboros.Network.Protocol.Handshake.Type
import Ouroboros.Network.Protocol.Handshake.Version
handshakeClientPeer
:: ( Ord vNumber
)
=> VersionDataCodec CBOR.Term vNumber vData
-> (vData -> vData -> Accept vData)
-> Versions vNumber vData r
-> Client (Handshake vNumber CBOR.Term)
NonPipelined StPropose m
(Either
(HandshakeProtocolError vNumber)
(HandshakeResult r vNumber vData))
handshakeClientPeer :: forall vNumber vData r (m :: * -> *).
Ord vNumber =>
VersionDataCodec Term vNumber vData
-> (vData -> vData -> Accept vData)
-> Versions vNumber vData r
-> Client
(Handshake vNumber Term)
'NonPipelined
'StPropose
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
handshakeClientPeer codec :: VersionDataCodec Term vNumber vData
codec@VersionDataCodec {vNumber -> vData -> Term
encodeData :: vNumber -> vData -> Term
encodeData :: forall bytes vNumber vData.
VersionDataCodec bytes vNumber vData -> vNumber -> vData -> bytes
encodeData, vNumber -> Term -> Either Text vData
decodeData :: vNumber -> Term -> Either Text vData
decodeData :: forall bytes vNumber vData.
VersionDataCodec bytes vNumber vData
-> vNumber -> bytes -> Either Text vData
decodeData}
vData -> vData -> Accept vData
acceptVersion Versions vNumber vData r
versions =
Message (Handshake vNumber Term) 'StPropose 'StConfirm
-> Client
(Handshake vNumber Term)
'NonPipelined
'StConfirm
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
-> Client
(Handshake vNumber Term)
'NonPipelined
'StPropose
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a
(st' :: ps).
(StateTokenI st, StateTokenI st', StateAgency st ~ 'ClientAgency,
Outstanding pl ~ 'Z) =>
Message ps st st' -> Client ps pl st' m a -> Client ps pl st m a
Yield (Map vNumber Term
-> Message (Handshake vNumber Term) 'StPropose 'StConfirm
forall vNumber1 vParams1.
Map vNumber1 vParams1
-> Message (Handshake vNumber1 vParams1) 'StPropose 'StConfirm
MsgProposeVersions (Map vNumber Term
-> Message (Handshake vNumber Term) 'StPropose 'StConfirm)
-> Map vNumber Term
-> Message (Handshake vNumber Term) 'StPropose 'StConfirm
forall a b. (a -> b) -> a -> b
$ (vNumber -> vData -> Term)
-> Versions vNumber vData r -> Map vNumber Term
forall vNumber r vParams vData.
(vNumber -> vData -> vParams)
-> Versions vNumber vData r -> Map vNumber vParams
encodeVersions vNumber -> vData -> Term
encodeData Versions vNumber vData r
versions) (Client
(Handshake vNumber Term)
'NonPipelined
'StConfirm
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
-> Client
(Handshake vNumber Term)
'NonPipelined
'StPropose
m
(Either
(HandshakeProtocolError vNumber)
(HandshakeResult r vNumber vData)))
-> Client
(Handshake vNumber Term)
'NonPipelined
'StConfirm
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
-> Client
(Handshake vNumber Term)
'NonPipelined
'StPropose
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall a b. (a -> b) -> a -> b
$
(forall (st' :: Handshake vNumber Term).
Message (Handshake vNumber Term) 'StConfirm st'
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber)
(HandshakeResult r vNumber vData)))
-> Client
(Handshake vNumber Term)
'NonPipelined
'StConfirm
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'ServerAgency,
Outstanding pl ~ 'Z) =>
(forall (st' :: ps). Message ps st st' -> Client ps pl st' m a)
-> Client ps pl st m a
Await ((forall (st' :: Handshake vNumber Term).
Message (Handshake vNumber Term) 'StConfirm st'
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber)
(HandshakeResult r vNumber vData)))
-> Client
(Handshake vNumber Term)
'NonPipelined
'StConfirm
m
(Either
(HandshakeProtocolError vNumber)
(HandshakeResult r vNumber vData)))
-> (forall (st' :: Handshake vNumber Term).
Message (Handshake vNumber Term) 'StConfirm st'
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber)
(HandshakeResult r vNumber vData)))
-> Client
(Handshake vNumber Term)
'NonPipelined
'StConfirm
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall a b. (a -> b) -> a -> b
$ \Message (Handshake vNumber Term) 'StConfirm st'
msg -> case Message (Handshake vNumber Term) 'StConfirm st'
msg of
MsgReplyVersions Map vNumber1 vParams1
vMap ->
Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'NobodyAgency,
Outstanding pl ~ 'Z) =>
a -> Client ps pl st m a
Done (Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber)
(HandshakeResult r vNumber vData)))
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall a b. (a -> b) -> a -> b
$ case VersionDataCodec Term vNumber vData
-> (vData -> vData -> Accept vData)
-> Versions vNumber vData r
-> Map vNumber Term
-> Either (RefuseReason vNumber) (r, vNumber, vData)
forall vParams vNumber vData r.
Ord vNumber =>
VersionDataCodec vParams vNumber vData
-> (vData -> vData -> Accept vData)
-> Versions vNumber vData r
-> Map vNumber vParams
-> Either (RefuseReason vNumber) (r, vNumber, vData)
acceptOrRefuse VersionDataCodec Term vNumber vData
codec vData -> vData -> Accept vData
acceptVersion Versions vNumber vData r
versions Map vNumber Term
Map vNumber1 vParams1
vMap of
Right (r
r, vNumber
vNumber, vData
vData) -> HandshakeResult r vNumber vData
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. b -> Either a b
Right (HandshakeResult r vNumber vData
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
-> HandshakeResult r vNumber vData
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. (a -> b) -> a -> b
$ r -> vNumber -> vData -> HandshakeResult r vNumber vData
forall r vNumber vData.
r -> vNumber -> vData -> HandshakeResult r vNumber vData
HandshakeNegotiationResult r
r vNumber
vNumber vData
vData
Left RefuseReason vNumber
vReason -> HandshakeProtocolError vNumber
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. a -> Either a b
Left (RefuseReason vNumber -> HandshakeProtocolError vNumber
forall vNumber.
RefuseReason vNumber -> HandshakeProtocolError vNumber
HandshakeError RefuseReason vNumber
vReason)
MsgQueryReply Map vNumber1 vParams1
vMap ->
Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'NobodyAgency,
Outstanding pl ~ 'Z) =>
a -> Client ps pl st m a
Done (Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber)
(HandshakeResult r vNumber vData)))
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall a b. (a -> b) -> a -> b
$ HandshakeResult r vNumber vData
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. b -> Either a b
Right (HandshakeResult r vNumber vData
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
-> HandshakeResult r vNumber vData
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. (a -> b) -> a -> b
$ (vNumber -> Term -> Either Text vData)
-> Map vNumber Term -> HandshakeResult r vNumber vData
forall vNumber bytes vData r.
(vNumber -> bytes -> Either Text vData)
-> Map vNumber bytes -> HandshakeResult r vNumber vData
decodeQueryResult vNumber -> Term -> Either Text vData
decodeData Map vNumber Term
Map vNumber1 vParams1
vMap
MsgRefuse RefuseReason vNumber1
vReason ->
Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'NobodyAgency,
Outstanding pl ~ 'Z) =>
a -> Client ps pl st m a
Done (HandshakeProtocolError vNumber
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. a -> Either a b
Left (HandshakeProtocolError vNumber
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
-> HandshakeProtocolError vNumber
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. (a -> b) -> a -> b
$ RefuseReason vNumber -> HandshakeProtocolError vNumber
forall vNumber.
RefuseReason vNumber -> HandshakeProtocolError vNumber
HandshakeError RefuseReason vNumber
RefuseReason vNumber1
vReason)
MsgAcceptVersion vNumber1
vNumber vParams1
vParams ->
case vNumber1
vNumber vNumber1
-> Map vNumber1 (Version vData r) -> Maybe (Version vData r)
forall k a. Ord k => k -> Map k a -> Maybe a
`Map.lookup` Versions vNumber1 vData r -> Map vNumber1 (Version vData r)
forall vNum vData r.
Versions vNum vData r -> Map vNum (Version vData r)
getVersions Versions vNumber vData r
Versions vNumber1 vData r
versions of
Maybe (Version vData r)
Nothing -> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'NobodyAgency,
Outstanding pl ~ 'Z) =>
a -> Client ps pl st m a
Done (HandshakeProtocolError vNumber
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. a -> Either a b
Left (HandshakeProtocolError vNumber
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
-> HandshakeProtocolError vNumber
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. (a -> b) -> a -> b
$ vNumber -> HandshakeProtocolError vNumber
forall vNumber. vNumber -> HandshakeProtocolError vNumber
NotRecognisedVersion vNumber
vNumber1
vNumber)
Just (Version vData -> r
app vData
vData) ->
case vNumber -> Term -> Either Text vData
decodeData vNumber
vNumber1
vNumber vParams1
Term
vParams of
Left Text
err ->
Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'NobodyAgency,
Outstanding pl ~ 'Z) =>
a -> Client ps pl st m a
Done (HandshakeProtocolError vNumber
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. a -> Either a b
Left (RefuseReason vNumber -> HandshakeProtocolError vNumber
forall vNumber.
RefuseReason vNumber -> HandshakeProtocolError vNumber
HandshakeError (RefuseReason vNumber -> HandshakeProtocolError vNumber)
-> RefuseReason vNumber -> HandshakeProtocolError vNumber
forall a b. (a -> b) -> a -> b
$ vNumber -> Text -> RefuseReason vNumber
forall vNumber. vNumber -> Text -> RefuseReason vNumber
HandshakeDecodeError vNumber
vNumber1
vNumber Text
err))
Right vData
vData' ->
case vData -> vData -> Accept vData
acceptVersion vData
vData vData
vData' of
Accept vData
agreedData ->
Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'NobodyAgency,
Outstanding pl ~ 'Z) =>
a -> Client ps pl st m a
Done (Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber)
(HandshakeResult r vNumber vData)))
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall a b. (a -> b) -> a -> b
$ HandshakeResult r vNumber vData
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. b -> Either a b
Right (HandshakeResult r vNumber vData
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
-> HandshakeResult r vNumber vData
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. (a -> b) -> a -> b
$ r -> vNumber -> vData -> HandshakeResult r vNumber vData
forall r vNumber vData.
r -> vNumber -> vData -> HandshakeResult r vNumber vData
HandshakeNegotiationResult (vData -> r
app vData
agreedData)
vNumber
vNumber1
vNumber
vData
agreedData
Refuse Text
err ->
Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
-> Client
(Handshake vNumber Term)
'NonPipelined
st'
m
(Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData))
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'NobodyAgency,
Outstanding pl ~ 'Z) =>
a -> Client ps pl st m a
Done (HandshakeProtocolError vNumber
-> Either
(HandshakeProtocolError vNumber) (HandshakeResult r vNumber vData)
forall a b. a -> Either a b
Left (vNumber -> Text -> HandshakeProtocolError vNumber
forall vNumber. vNumber -> Text -> HandshakeProtocolError vNumber
InvalidServerSelection vNumber
vNumber1
vNumber Text
err))
decodeQueryResult :: (vNumber -> bytes -> Either Text vData)
-> Map vNumber bytes
-> HandshakeResult r vNumber vData
decodeQueryResult :: forall vNumber bytes vData r.
(vNumber -> bytes -> Either Text vData)
-> Map vNumber bytes -> HandshakeResult r vNumber vData
decodeQueryResult vNumber -> bytes -> Either Text vData
decodeData Map vNumber bytes
vMap = Map vNumber (Either Text vData) -> HandshakeResult r vNumber vData
forall r vNumber vData.
Map vNumber (Either Text vData) -> HandshakeResult r vNumber vData
HandshakeQueryResult (Map vNumber (Either Text vData)
-> HandshakeResult r vNumber vData)
-> Map vNumber (Either Text vData)
-> HandshakeResult r vNumber vData
forall a b. (a -> b) -> a -> b
$ (vNumber -> bytes -> Either Text vData)
-> Map vNumber bytes -> Map vNumber (Either Text vData)
forall k a b. (k -> a -> b) -> Map k a -> Map k b
Map.mapWithKey vNumber -> bytes -> Either Text vData
decodeData Map vNumber bytes
vMap
encodeVersions
:: forall vNumber r vParams vData.
(vNumber -> vData -> vParams)
-> Versions vNumber vData r
-> Map vNumber vParams
encodeVersions :: forall vNumber r vParams vData.
(vNumber -> vData -> vParams)
-> Versions vNumber vData r -> Map vNumber vParams
encodeVersions vNumber -> vData -> vParams
encoder (Versions Map vNumber (Version vData r)
vs) = vNumber -> Version vData r -> vParams
go (vNumber -> Version vData r -> vParams)
-> Map vNumber (Version vData r) -> Map vNumber vParams
forall k a b. (k -> a -> b) -> Map k a -> Map k b
`Map.mapWithKey` Map vNumber (Version vData r)
vs
where
go :: vNumber -> Version vData r -> vParams
go :: vNumber -> Version vData r -> vParams
go vNumber
vNumber Version {vData
versionData :: vData
versionData :: forall vData r. Version vData r -> vData
versionData} = vNumber -> vData -> vParams
encoder vNumber
vNumber vData
versionData
acceptOrRefuse
:: forall vParams vNumber vData r.
Ord vNumber
=> VersionDataCodec vParams vNumber vData
-> (vData -> vData -> Accept vData)
-> Versions vNumber vData r
-> Map vNumber vParams
-> Either (RefuseReason vNumber) (r, vNumber, vData)
acceptOrRefuse :: forall vParams vNumber vData r.
Ord vNumber =>
VersionDataCodec vParams vNumber vData
-> (vData -> vData -> Accept vData)
-> Versions vNumber vData r
-> Map vNumber vParams
-> Either (RefuseReason vNumber) (r, vNumber, vData)
acceptOrRefuse VersionDataCodec {vNumber -> vParams -> Either Text vData
decodeData :: forall bytes vNumber vData.
VersionDataCodec bytes vNumber vData
-> vNumber -> bytes -> Either Text vData
decodeData :: vNumber -> vParams -> Either Text vData
decodeData}
vData -> vData -> Accept vData
acceptVersion Versions vNumber vData r
versions Map vNumber vParams
versionMap =
case Map vNumber vParams
-> Map vNumber (Version vData r)
-> Maybe (vNumber, (vParams, Version vData r))
forall k a b. Ord k => Map k a -> Map k b -> Maybe (k, (a, b))
lookupGreatestCommonKey Map vNumber vParams
versionMap (Versions vNumber vData r -> Map vNumber (Version vData r)
forall vNum vData r.
Versions vNum vData r -> Map vNum (Version vData r)
getVersions Versions vNumber vData r
versions) of
Maybe (vNumber, (vParams, Version vData r))
Nothing ->
RefuseReason vNumber
-> Either (RefuseReason vNumber) (r, vNumber, vData)
forall a b. a -> Either a b
Left (RefuseReason vNumber
-> Either (RefuseReason vNumber) (r, vNumber, vData))
-> RefuseReason vNumber
-> Either (RefuseReason vNumber) (r, vNumber, vData)
forall a b. (a -> b) -> a -> b
$ [vNumber] -> [Int] -> RefuseReason vNumber
forall vNumber. [vNumber] -> [Int] -> RefuseReason vNumber
VersionMismatch (Map vNumber (Version vData r) -> [vNumber]
forall k a. Map k a -> [k]
Map.keys (Map vNumber (Version vData r) -> [vNumber])
-> Map vNumber (Version vData r) -> [vNumber]
forall a b. (a -> b) -> a -> b
$ Versions vNumber vData r -> Map vNumber (Version vData r)
forall vNum vData r.
Versions vNum vData r -> Map vNum (Version vData r)
getVersions Versions vNumber vData r
versions) []
Just (vNumber
vNumber, (vParams
vParams, Version vData -> r
app vData
vData)) ->
case vNumber -> vParams -> Either Text vData
decodeData vNumber
vNumber vParams
vParams of
Left Text
err ->
RefuseReason vNumber
-> Either (RefuseReason vNumber) (r, vNumber, vData)
forall a b. a -> Either a b
Left (vNumber -> Text -> RefuseReason vNumber
forall vNumber. vNumber -> Text -> RefuseReason vNumber
HandshakeDecodeError vNumber
vNumber Text
err)
Right vData
vData' ->
case vData -> vData -> Accept vData
acceptVersion vData
vData vData
vData' of
Accept vData
agreedData ->
(r, vNumber, vData)
-> Either (RefuseReason vNumber) (r, vNumber, vData)
forall a b. b -> Either a b
Right (vData -> r
app vData
agreedData, vNumber
vNumber, vData
agreedData)
Refuse Text
err ->
RefuseReason vNumber
-> Either (RefuseReason vNumber) (r, vNumber, vData)
forall a b. a -> Either a b
Left (vNumber -> Text -> RefuseReason vNumber
forall vNumber. vNumber -> Text -> RefuseReason vNumber
Refused vNumber
vNumber Text
err)
lookupGreatestCommonKey :: Ord k => Map k a -> Map k b -> Maybe (k, (a, b))
lookupGreatestCommonKey :: forall k a b. Ord k => Map k a -> Map k b -> Maybe (k, (a, b))
lookupGreatestCommonKey Map k a
l Map k b
r = Map k (a, b) -> Maybe (k, (a, b))
forall k a. Map k a -> Maybe (k, a)
Map.lookupMax (Map k (a, b) -> Maybe (k, (a, b)))
-> Map k (a, b) -> Maybe (k, (a, b))
forall a b. (a -> b) -> a -> b
$ (a -> b -> (a, b)) -> Map k a -> Map k b -> Map k (a, b)
forall k a b c.
Ord k =>
(a -> b -> c) -> Map k a -> Map k b -> Map k c
Map.intersectionWith (,) Map k a
l Map k b
r