长代码示例的道歉,请参阅第30行:A.openDeviceCallback =
。 micSpec
是A.OpenDeviceSpec类型对象的工厂函数。我对这个函数的参数列表不满意。
{-# OPTIONS_GHC -Wall #-}
-- Dependant on cabal packages: sdl2, wave.
module Main where
import qualified Control.Concurrent as C
--import qualified Control.Monad as M
import qualified Data.Vector.Storable.Mutable as V
import qualified Data.Set as S
import Foreign.ForeignPtr as P
import qualified SDL
import qualified SDL.Audio as A
import qualified Codec.Audio.Wave as W
import qualified System.IO as IO
import qualified Statistics.Sample as St
micSpec :: IO.Handle -> A.OpenDeviceSpec
micSpec h = A.OpenDeviceSpec {A.openDeviceFreq = A.Mandate 48000
,A.openDeviceFormat = A.Mandate A.Signed16BitNativeAudio
,A.openDeviceChannels = A.Mandate A.Mono
,A.openDeviceSamples = 4096
,A.openDeviceCallback = \_ (V.MVector size ptr) -> P.withForeignPtr ptr (\p -> IO.hPutBuf h p size)
,A.openDeviceUsage = A.ForCapture
,A.openDeviceName = Nothing}
waveSpec :: W.Wave
waveSpec = W.Wave {W.waveFileFormat = W.WaveVanilla
, W.waveSampleRate = 48000
, W.waveSampleFormat = W.SampleFormatPcmInt 16
, W.waveChannelMask = S.singleton W.SpeakerFrontCenter
, W.waveDataOffset = 0
, W.waveDataSize = 0
, W.waveSamplesTotal = 0
, W.waveOtherChunks = []}
record :: IO.Handle -> IO ()
record h = do
SDL.initialize [SDL.InitAudio]
(dev, _) <- A.openAudioDevice $ micSpec h
A.setAudioDevicePlaybackState dev A.Play
-- _ <- M.forever (C.threadDelay maxBound)
_ <- C.threadDelay 10000000
return ()
main :: IO ()
main = W.writeWaveFile "mic.rec" waveSpec record
在这样一个简单程序的上下文中,所需的A.OpenDeviceSpec
对象是一组常量,还有一个动作。目前,该行动正在内联构建......因为这是我设法定义它的唯一方式,而不传递类型信息。
我对C的直觉是
type Cb = A.AudioFormat t -> A.IOVector t -> IO ()
micSpec :: Cb -> A.OpenDeviceSpec
,但我无法使其发挥作用。
答案 0 :(得分:0)
显然,您的问题与通用量化字段
有关data OpenDeviceSpec = OpenDeviceSpec {
...
, openDeviceCallback :: forall actualSampleType. AudioFormat actualSampleType -> IOVector actualSampleType -> IO ()
, ...
}
......或者,因为它可以更简单地写,
data OpenDeviceSpec = OpenDeviceSpec {
...
, openDeviceCallback :: ∀ sT . AudioFormat sT -> IOVector sT -> IO ()
, ...
}
不用担心,这并不困难。实际上,所有标准多态函数都隐含了这样的∀
,例如
map :: (a -> b) -> [a] -> [b]
实际上是†的简写
map :: ∀ a b . (a -> b) -> [a] -> [b]
同样,要定义回调,您只需确保样本类型中的多态“。即。
openingCallback :: IO.Handle -> A.AudioFormat sT -> V.IOVector sT -> IO ()
openingCallback _ (V.MVector size ptr)
= P.withForeignPtr ptr $ \p -> IO.hPutBuf h p size
然后
micSpec h = A.OpenDeviceSpec {
...
,A.openDeviceCallback = openingCallback h
,...
}
如果您希望将openingCallback
作为micSpec
的参数,则需要对该参数进行普遍量化。与记录字段一样,与顶级绑定不同,必须使用显式量子声明参数是通用的:
{-# LANGUAGE Rank2Types, UnicodeSyntax #-}
micSpec :: (∀ sT . A.AudioFormat sT -> V.IOVector sT -> IO ())
-> A.OpenDeviceSpec
micSpec openingCallback
= A.OpenDeviceSpec {
...
,A.openDeviceCallback = openingCallback
,...
}
† 嗯,我不确定用这种方式是否真的有意义,因为∀
在Haskell98中甚至不合法。通用量词仍然是应该如何读取所有多态签名。