FIFO 큐를 설명하는 하스켈 타입 클래스 (또는 타입 클래스의 조합이있다)를 작성한 사람이 있는가?큐를위한 하스켈 타입 클래스
Data.Collection.Sequence은 너무 강하지 만 다른 한편으로는 Data.Collection.Unfoldable이 약해 보입니다 (순서가 정의되지 않았 음).
나는 다른 사람의 작업을 다시하고 싶지 않습니다.
FIFO 큐를 설명하는 하스켈 타입 클래스 (또는 타입 클래스의 조합이있다)를 작성한 사람이 있는가?큐를위한 하스켈 타입 클래스
Data.Collection.Sequence은 너무 강하지 만 다른 한편으로는 Data.Collection.Unfoldable이 약해 보입니다 (순서가 정의되지 않았 음).
나는 다른 사람의 작업을 다시하고 싶지 않습니다.
하스켈에서 FIFO 대기열을 롤업하는 것은 실제로 어렵지 않습니다. 나는 당신이 이것을 위해 표준 typeclass를 사용하고 싶어하는 것에 대해 감사 할 수있다. 그리고 그것은 당신이해야하는 거의 확실한 것이다. 그러나 저는 지난 주에 대해 배웠습니다. 나는 그것에 대해 쓰지 않기에 너무나 기쁩니다.
다음은 간단한 대기열 클래스입니다.이 클래스를 사용하면 대기열이 비어 있는지 확인할 수 있습니다. 대기열의 첫 번째 요소를 가져 와서 나머지 대기열을 반환하고 새 요소를 대기열에 삽입 할 수 있습니다 .
class Queue q where
empty :: q a -> Bool
get :: q a -> (a, q a)
ins :: a -> q a -> q a
는 FIFO 큐를 확인하는 가장 간단한 방법
이 목록을 사용하고 있습니다 :instance Queue [] where
empty = null
get [] = error "Can't retrieve elements from an empty list"
get (x:xs) = (x, xs)
ins x xs = xs ++ [x]
그러나,이 끔찍하게 비효율적이다. 큐에 현재 n 요소가있는 경우 새 요소를 삽입하려면 O (n) 시간이 걸립니다. 빈 큐에 m 요소를 삽입하려면 O (m) 시간이 필요합니다. O (1) 시간 (또는 최소, O (1) 상각 시간)에 요소를 삽입하고 검색하는 대기열을 만들 수 있습니까?
data Fifo a = F [a] [a]
instance Queue Fifo where
큐 앞뒤 양쪽 경우 비어 :
트릭 역방향에 저장되는 큐의 후면과 전면 분리 목록에 큐 다시 저장하는 것이다 비어 있음 :
empty (F xs ys) = null xs && null ys
새 요소를 목록에 삽입하려면 O (1) 시간이 소요되는 대기열에 넣으십시오. 거기에 대기 요소 (이 큐가 비어있는 경우 우리가 오류가 발생)에 요소가없는 경우,
get (F [] []) = error "Can't retrieve elements from an empty queue"
get (F (x:xs) ys) = (x, F xs ys)
마지막 때 큐의 앞쪽에서 요소를 얻기
는ins y (F xs ys) = F xs (y:ys)
쉽게 대기열의 앞에서 기다린 다음 대기열의 뒤를 뒤집어서 앞에 놓습니다. (O 상각 -
get (F [] ys) = get (F (reverse ys) [])
이
당신이 한 :이 O를 취했지만 (N) 시간, 우리는 그래서 우리의 GET 작업의 평균 (1) 시간 O 밖으로, 각 요소에 대해 한 번해야 1) 기능적 언어로 FIFO 대기열.
편집 :는 Efie는 코멘트에 상각 O (1)의 성능에 대해 물었다. 상각 된 상수 시간에 대한 논의는 매우 간단합니다.
n 빈 큐에 대한 삽입 다음에 n 검색이 이어지는 것으로 간주하십시오. 삽입은 시간이 n 걸립니다. 첫 번째 검색에서 대기열의 앞면이 비어 있으므로 대기열의 뒤를 되돌려 야합니다. 또한 n에 1을 더하여 요소를 검색합니다. 우리가 만든 1 = 3 N
- 마지막으로, 다음 N - 총 시간은
N + N + 1 + N 그래서 1 취득에서는이 시간이 1 각을 2 n 총 호출이므로 상환 시간은 3 (n/2 n = 3/2)이며 O (1)입니다. ins
과 get
에 대한 호출이 어떻게 인터리브되었는지에 상관없이 동일한 인수가 작동합니다. 두 번의 호출에서 각 요소는 한 번에 한 번에 한 번만 이동되고 한 번만 이동하고 한 번만 수행 할 수 있습니다.
감사합니다. 나는 귀하의 게시물을 좋아합니다. 오류가 발생하지 않도록 요소를 가져 오기 전에 매번 목록이 null인지 확인해야합니다. 그렇지 않습니까? get :: q a -> (get a, q a)의 형식을 변경하는 것보다 낫습니까? – efie
'안전한'방법은 형식을'get :: qa -> Maybe (a, qa)'로 변경하는 것입니다 (튜플을 감싸는'Maybe '로 나머지 부분을 반환하는 것은 의미가 없으므로). 첫 번째 요소를 검색하지 못한 경우 대기열). 구현을 간단하게하기 위해 이것을 무시 했으므로 코드를 안전하게 사용하기 전에 목록이 null인지 확인해야합니다. 'Maybe' 래퍼를 사용하면 호출 후'Nothing' *을 확인해야하므로이 작업은 더 이상 필요하지 않습니다. 그러나 래퍼를 사용하면 형식 시스템에서 확인하지 않아도되므로 안전하지 않은 코드를 작성할 수 있습니다. –
요소를 가져 오는 평균적인 경우가 O (1) 인 경우를 확장하고 싶습니다. 큐에 n 개의 요소가 있으면 (n + 1) 개 있습니다! 그들을 두 개의 목록에 할당하는 방법 : n! n 개의 요소를 정렬하는 방법, 각 배열을 두 개의 목록으로 나누는 (n + 1) 개의 방법. n이 있습니다! xs가 비어있는 경우 ys에 요소를 정렬하는 방법. probes ("xsIsEmpty") * 비용 ("xsIsEmpty") + prob ("xsNotEmpty") * 비용 ("xsNotEmpty") = n!/(n + 1)! * n + ... * 0 = n/n + 1 = O (1). – efie