Đầu tiên, một phiên bản đơn giản của tác vụ tôi muốn thực hiện: Tôi có một số tệp lớn (lên đến 30 GB) mà tôi muốn cắt tỉa cho các mục trùng lặp. Để kết thúc này, tôi thiết lập một cơ sở dữ liệu của băm dữ liệu và mở từng tệp một, băm nhỏ từng mục và ghi nó vào cơ sở dữ liệu và tệp đầu ra iff băm của nó chưa có trong cơ sở dữ liệu.Sử dụng liên tục từ bên trong một Conduit
Tôi biết cách thực hiện điều này với lặp lại, điều tra viên và tôi muốn thử ống dẫn. Tôi cũng biết làm thế nào để làm điều đó với ống dẫn, nhưng bây giờ tôi muốn sử dụng ống dẫn & dai dẳng. Tôi đang gặp sự cố với các loại và có thể với toàn bộ khái niệm là ResourceT
.
Dưới đây là một số mã giả để minh họa cho vấn đề:
withSqlConn "foo.db" $ runSqlConn $ runResourceT $
sourceFile "in" $= parseBytes $= dbAction $= serialize $$ sinkFile "out"
Vấn đề nằm ở chỗ dbAction
chức năng. Tôi muốn truy cập vào cơ sở dữ liệu ở đây, một cách tự nhiên. Kể từ khi hoạt động nó làm là về cơ bản chỉ là một bộ lọc, đầu tiên tôi nghĩ để viết nó như thế:
dbAction = CL.mapMaybeM p
where p :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) => DataType -> m (Maybe DataType)
p = lift $ putStrLn "foo" -- fine
insert $ undefined -- type error!
return undefined
Các lỗi cụ thể tôi nhận được là:
Could not deduce (m ~ b0 m0)
from the context (MonadIO m, MonadBaseControl IO (SqlPersist m))
bound by the type signature for
p :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) =>
DataType -> m (Maybe DataType)
at tools/clean-wac.hs:(33,1)-(34,34)
`m' is a rigid type variable bound by
the type signature for
p :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) =>
DataType -> m (Maybe (DataType))
at tools/clean-wac.hs:33:1
Expected type: m (Key b0 val0)
Actual type: b0 m0 (Key b0 val0)
Lưu ý rằng điều này có thể là do những giả định sai Tôi đã thiết kế chữ ký kiểu. Nếu tôi nhận xét ra chữ ký kiểu và cũng loại bỏ các tuyên bố lift
, thông báo lỗi biến thành:
No instance for (PersistStore ResourceT (SqlPersist IO))
arising from a use of `p'
Possible fix:
add an instance declaration for
(PersistStore ResourceT (SqlPersist IO))
In the first argument of `CL.mapMaybeM', namely `p'
Vì vậy, điều này có nghĩa rằng chúng ta không thể truy cập vào PersistStore
ở tất cả qua ResourceT
?
tôi không thể viết Conduit của riêng tôi, hoặc, mà không sử dụng CL.mapMaybeM
:
dbAction = filterP
filterP :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) => Conduit DataType m DataType
filterP = loop
where loop = awaitE >>= either return go
go s = do lift $ insert $ undefined -- again, type error
loop
Điều này dẫn đến thêm một lỗi loại I không hoàn toàn hiểu.
Could not deduce (m ~ b0 m0)
from the context (MonadIO m, MonadBaseControl IO (SqlPersist m))
bound by the type signature for
filterP :: (MonadIO m,
MonadBaseControl IO (SqlPersist m)) =>
Conduit DataType m DataType
`m' is a rigid type variable bound by
the type signature for
filterP :: (MonadIO m,
MonadBaseControl IO (SqlPersist m)) =>
Conduit DataType m DataType
Expected type: Conduit DataType m DataType
Actual type: Pipe
DataType DataType DataType() (b0 m0)()
In the expression: loop
In an equation for `filterP'
Vì vậy, câu hỏi của tôi là: có thể sử dụng liên tục như tôi định dùng trong ống dẫn không? Và nếu, làm thế nào? Tôi biết rằng vì tôi có thể sử dụng liftIO
bên trong ống dẫn, tôi chỉ có thể sử dụng và nói, HDBC
, nhưng tôi muốn sử dụng liên tục một cách rõ ràng để hiểu cách hoạt động và vì tôi thích chủ nghĩa bất khả tri của chương trình phụ trợ db.
bạn đã thử sử dụng 'lift' thay vì' liftIO'? –
Ah, vâng, chắc chắn 'liftIO' áp đặt một ràng buộc đối với toàn bộ khối' do'. Nhưng điều đó chỉ giải thích tại sao thông báo lỗi đầu tiên khác với thông báo thứ hai. Tôi sẽ cập nhật bài đăng trong giây lát, để phản ánh điều gì sẽ xảy ra nếu bạn xóa câu lệnh liftIO. –
BTW, thậm chí 'lift' đã áp đặt hạn chế' IO' đối với loại đơn nguyên. Tôi lưu ý bạn phải * loại bỏ * lệnh 'lift' hoàn toàn để đạt được thông báo lỗi đó. Nếu bạn không (nhưng giữ 'lift $ print" "' in), bạn sẽ nhận được 'Không thể khớp với kiểu được mong đợi 'SqlPersist m0 a0' với kiểu thực tế 'IO()''. –