{-# LANGUAGE Safe #-}--------------------------------------------------------------------------------moduleControl.Asynchronous(ForeignThreadInterface,Fork,fork,join,sync)where--------------------------------------------------------------------------------importControl.Concurrent(ThreadId,forkFinally)importControl.Concurrent.MVar(MVar,newEmptyMVar,putMVar,readMVar)importGHC.Exception(SomeException,throw)--------------------------------------------------------------------------------dataForka=Fork!ThreadId(IO(EitherSomeExceptiona))---------------------------------------------------------------------------------- To prevent the users from adding instances of `ForeignThreadInterface`, we-- provide a middle-layer (`ASYNC`) between the `Monad` instance and the `Proxy`-- (`ForeignThreadInterface`) instance.classMonadm=>ASYNCmwherenew::m(MVara)put::MVara->a->m( )get::MVara->maclassASYNCm=>ForeignThreadInterfacemwherefork::ma->m(Forka)join::Forka->masync::[Forka]->m( )--------------------------------------------------------------------------------instanceASYNCIOwhere-- newEmptyMVar: Create an MVar which is initially empty.new=newEmptyMVar-- putMVar: Put a value into an MVar.put=putMVar-- readMVar: Atomically read the contents of an MVar. If the MVar is currently-- empty, readMVar will wait until it is full. readMVar is guaranteed to-- receive the next putMVar.get=readMVarinstanceForeignThreadInterfaceIOwherefork=\compute->new>>=\var->forkFinallycompute(finallyvar)>>=\tid->pure$Forktid$getvarwherefinallyv=\r->putvrjoin(Fork_mvar)=mvar>>=\var->casevarofRightv->purevLefte->throwesync=mapM_join
{-# LANGUAGE RankNTypes #-}{-# LANGUAGE Safe #-}--------------------------------------------------------------------------------moduleData.Bitonic(Sortable,SortableTrust,sort)where--------------------------------------------------------------------------------importData.Bits(countLeadingZeros,finiteBitSize,shiftL,shiftR,(.&.))importqualifiedForeign.Marshal.AllocasFFIimportForeign.Ptr(Ptr,plusPtr)importForeign.Storable(Storable)importqualifiedForeign.StorableasFFIimportControl.Asynchronous(ForeignThreadInterface,fork,sync)---------------------------------------------------------------------------------- To prevent the users from adding instances of `ForeignMemoryInterface`, we-- provide a middle-layer (`FMEMI`) between the `Monad` instance and the `Proxy`-- (`ForeignMemoryInterface`) instance.---- Note: This is redundant as by using `RankNTypes` to create a type alias and-- expose that type from the module instead.classMonadm=>FMEMImclassFMEMIm=>ForeignMemoryInterfacemwheremalloc::Storablea=>Int->m(Ptra)free::Storablea=>Ptra->m( )peek::Storablea=>Ptra->Int->mapoke::Storablea=>Ptra->Int->a->m( )--------------------------------------------------------------------------------typeSortableaio=(Storablea,Orda,ForeignMemoryInterfaceio,ForeignThreadInterfaceio)=>[a]->io[a]typeSortableTrusta=(Storablea,Orda)=>[a]->[a]typeOffSet=InttypeLength=Int--------------------------------------------------------------------------------instanceFMEMIIOinstanceForeignMemoryInterfaceIOwheremalloc=FFI.mallocBytesfree=FFI.freepeek=FFI.peekElemOffpoke=FFI.pokeElemOff--------------------------------------------------------------------------------sort::Sortableaiosort[ ]=pure[]sortxs@(hd:_)=mallocm>>=\p->storep0ys>>=\_->-- initiate memory values to the list max valuestorep0xs>>=\_->sorterpon>>=\_->querypn>>=\zs->freep>>=\_->pure$takelzswherel=lengthxsn=pow2l-- Ensure that allocated memory is 2^io=FFI.sizeOfhdm=n*oys=taken$cycle[foldl1maxxs]--------------------------------------------------------------------------------query::(Storablea,ForeignMemoryInterfaceio)=>Ptra->Length->io[a]querypn=aux0whereauxi|i<n=aux(i+1)>>=\tl->peekpi>>=\hd->pure$hd:tl|otherwise=pure[]store::(Storablea,ForeignMemoryInterfaceio)=>Ptra->OffSet->[a]->io()store__[ ]=pure()storepi(x:xs)=pokepix>>storep(i+1)xs--------------------------------------------------------------------------------pow2::Int->Intpow2x=ifx.&.(x-1)==0thenxelse1`shiftL`(b-z)whereb=finiteBitSizexz=countLeadingZerosxnext::(Storablea)=>Ptra->OffSet->Ptranextpo=p`plusPtr`(1*o)`asTypeOf`pprev::(Storablea)=>Ptra->OffSet->Ptraprevpo=p`plusPtr`(-1*o)`asTypeOf`p--------------------------------------------------------------------------------sorter::(Storablea,Orda,ForeignMemoryInterfaceio,ForeignThreadInterfaceio)=>Ptra->OffSet->Length->io()sorterpon=(if2<nthenfork(sorterpom)>>=\f->fork(sorterqom)>>=\s->sync[f,s]elsepure())>>=\_->mergerponwherem=n`shiftR`1q=p`plusPtr`(m*o)`asTypeOf`pmerger::(Storablea,Orda,ForeignMemoryInterfaceio,ForeignThreadInterfaceio)=>Ptra->OffSet->Length->io()mergerpon=wp(prevlo)>>=\_->if2<nthenfork(bitonicpom)>>=\f->fork(bitonicqom)>>=\s->sync[f,s]elsepure()wherem=n`shiftR`1q=p`plusPtr`(m*o)`asTypeOf`pl=p`plusPtr`(n*o)`asTypeOf`pwij|i<q=fork(comparatorij)>>=\f->fork(w(nextio)(prevjo))>>=\s->sync[f,s]|otherwise=pure()comparator::(Storablea,Orda,ForeignMemoryInterfaceio)=>Ptra->Ptra->io()comparatorpq=peekp0>>=\i->peekq0>>=\j->pokep0(minij)>>=\_->pokeq0(maxij)>>=\_->pure()bitonic::(Storablea,Orda,ForeignMemoryInterfaceio,ForeignThreadInterfaceio)=>Ptra->OffSet->Length->io()bitonicpon=cleanerpon>>=\_->if2<nthenfork(bitonicpom)>>=\f->fork(bitonicqom)>>=\s->sync[f,s]elsepure()wherem=n`shiftR`1q=p`plusPtr`(m*o)`asTypeOf`pcleaner::(Storablea,Orda,ForeignMemoryInterfaceio,ForeignThreadInterfaceio)=>Ptra->OffSet->Length->io()cleanerpon=wpqwherem=n`shiftR`1q=p`plusPtr`(m*o)`asTypeOf`pwij|i<q=fork(comparatorij)>>=\f->fork(w(nextio)(nextjo))>>=\s->sync[f,s]|otherwise=pure()
#!/usr/bin/envstack{- stack
--resolver lts-12.0
--install-ghc
script
--ghc-options -Werror
--ghc-options -Wall
--
-}{-# LANGUAGE Trustworthy #-}--------------------------------------------------------------------------------moduleMain(main)where--------------------------------------------------------------------------------importSystem.IO.Unsafe(unsafePerformIO)importData.Bitonic(SortableTrust,sort)---------------------------------------------------------------------------------- In case you need the sorting algorithm to produce no IO effects, you will-- have to create your own local version by implementing the `SortableTrust`-- alias type with `unsafePerformIO`.trust::SortableTrustatrust=unsafePerformIO.sort--------------------------------------------------------------------------------main::IO()main=doputStrLn$"# Bitonic sort"putStrLn$"> xs (initial): "++(showxs)sortxs>>=putStrLn.("> ys (effects): "++).showputStrLn$"> zs (trusted): "++(show$trustxs)wherexs=reverse[0..15]::[Word]