여러 발신자와 수신자가 관련된 문제를 해결하려고 노력 중이며 내 접근 방식이 올바른 방향인지에 대한 피드백을 받고 싶습니다.
문제 : N 명의 리더와 M 명의 팔로워가 있는데 모두 개별 스레드로 대표되어야합니다. 모든 사람은 댄서이며 8 개의 다른 춤 이름이있는 "댄스 카드"를 가지고 있습니다. 각 리더는 추종자에게 특정 댄스를 추를 수 있는지 물어봐야합니다. 추종자들은 리더의 초대를 기다리고 이미 그 춤을 추지 않았고 다른 2 개의 춤을이 리더와 춤추는 데 동의하지 않은 경우에만 수락합니다. 리더가 초대가 수락되었다는 소식을 듣게되면 다음 댄스 경기를 확보하기 위해 계속 노력합니다. 그렇지 않으면 그들은 같은 춤에 대한 일치를 계속 찾으려고 노력합니다. 마지막으로 리더 "댄스 카드"에는 각 댄스와 함께 춤을 추는 추종자의 ID가 인쇄됩니다.
접근 방식 : 리더와 팔로워라는 두 가지 기능을 만들었습니다. 주로 forkIO를 사용하여 리더를 n 번, 팔로워를 m 번 호출합니다. 그러나 상태를 유지하는 방법 (특히 댄스 카드)에 대한 문제가 있습니다. 저는 "Dancer"유형 클래스를 만들고 두 가지 인스턴스 인 Leader와 Follower를 만들 생각 중이었습니다. 각 리더와 각 팔로워는 고유 ID (1에서 N 또는 M까지)를 갖습니다. 또한 각각의 개인 메일 함으로 사용할 mvar가 필요합니다. 리더는 동일한 팔로워가 그것을 꺼내고 초대에 예 또는 아니오로 응답 할 수 있도록 어떤 것을 넣기 위해 어떻게 든 팔로워의 mvar를 "가져올"필요가있을 것입니다. 댄스 카드에 관해서는 상태 모나드를 통합하는 것이 최선이라고 생각합니다. 예를 들어, 리더가 추종자를 댄스에 초대하면
와, 이미 타입 클래스, 두 개의 인스턴스, 상태 모나드가 있고 MVar의 타입도 정해지지 않았습니다! 상황이 복잡해지고 있습니다.
나는 당신이 Haskell-as-Java 함정에 빠지게 될지도 모른다고 걱정합니다. 여기서 당신은 당신의 머릿속에서 객체 지향 솔루션을 생각 해냈고, 이제 당신은 그것을 Haskell로 직접 번역하려고 노력하고 있습니다. 공유 메서드가 "클래스"등으로 래핑 된 상태 저장 개체
나는 다른 접근법을 제안 할 것입니다. 댄서는 "사물"이 아닙니다. 그들은 작업입니다. 관용적 Haskell에서 일반적으로 사용되는 것처럼 간단한 함수로 구현하고 "상태"대신 인수 전달 및 재귀를 사용합니다.
스포일러가 뒤 따르지만 여기에를 갖고 있고 id
요청 / 응답 MVar 쌍을 통해 요청에 응답하고 재귀 코어 루프를 사용하여 댄스 카드를 유지하는 "팔로어"를 정의하는 간단한 방법이 있습니다. 있습니다 Follower
데이터 형식 (예를 들어, 그것은 더 댄스 카드가 없음)는 "추종자 객체"있어야되지 않으며, follower
팔로어 작업을 식별하고 통신하기위한 "핸들"역할을하는 반환 값을 문서화하는 편리한 방법 일뿐입니다 .
type LeaderId = Int
type FollowerId = Int
type Dance = Int
-- |A dance card for a follower with a list of dance/leader pairs.
data Card = Card { getCard :: [(Dance, LeaderId)] } deriving (Show)
emptyCard = Card []
-- |Follower handle giving its id and request/response MVars
data Follower =
Follower { followerId :: FollowerId
, request :: MVar (Dance, LeaderId)
, response :: MVar Bool
}
-- |Create a new follower task with given id.
follower :: FollowerId -> IO Follower
follower followerId_ = do
req <- newEmptyMVar
res <- newEmptyMVar
let loop (Card xs) = do
-- get next request
(dance, leaderId_) <- takeMVar req
case lookup dance xs of
-- if dance is free and we haven't danced too often w/ this leader
Nothing | length (filter ((==leaderId_) . snd) xs) < 2
-- then say yes and update dance card
-> do putMVar res True
loop (Card $ (dance, leaderId_) : xs)
-- otherwise, refuse
_ -> do putMVar res False
loop (Card xs)
forkIO $ loop emptyCard
return $ Follower followerId_ req res
춤을 추도록 요청하여 두 명의 팔로워를 만들고 테스트 할 수 있습니다.
> f1 <- follower 1 -- follower #1
> f2 <- follower 2 -- follower #2
> putMVar (request f1) (1, 10) -- dance #1 w/ leader #10
> takeMVar (response f1)
True -- hooray!
> putMVar (request f1) (1, 14) -- dance #1 w/ leader #14
> takeMVar (response f1)
False -- wah! dance is taken
> putMVar (request f2) (1, 14) -- try different follower
> takeMVar (response f2)
True -- hooray!
>
이 특정 추종자들은 댄스 카드를 요청하거나 무한 루프를 종료하도록 지시 할 수 없습니다. 이 응용 프로그램에는 필요하지 않습니다 (우리는 리더의 댄스 카드 만 필요하며 답변을 얻을 때 많은 경량 스레드가 붙어 있더라도 상관하지 않습니다), 다음과 같은 경우 항상 몇 개의 MVar를 추가 할 수 있습니다. 당신은했다.
마찬가지로 간단한 재귀 코어 루프를 사용하여 리더를 함수로 구현할 수 있어야합니다. 리더가 순서대로 댄스 카드를 채우려 고하면 실제로 댄스 카드를 추적 할 필요가 없습니다. 최종 댄스 카드 (및 "코어 루프")는 mapM
너무 많이 시도합니다. 댄스 슬롯 1 ~ 8을 채 웁니다.
추종자에게 춤을 요청할 수있는 능력을 리더에게 어떻게 제공합니까? 글쎄, 먼저 전체 팔로어 세트를 만들고 팔로어 핸들 목록 ( [Follower]
)을 leader
생성 함수에 대한 인수로 전달 합니다. 지도자로부터 댄스 카드를 어떻게 되찾나요? leader
기능은 카드에 대한 MVAR을 반환해야하고, main
기능을 할 수있는 mapM takeMVar leadersDanceCards
댄스 카드의 전체 목록을 얻을 수 있습니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다