我有一个表示枚举的类型:
data FooBar = Foo | Bar deriving (Show, Enum)
我想使用aeson从JSON中的数字值对此进行解析,即JSON文件中的0应该返回Foo,1应该返回Bar。
我的最佳尝试是:
instance FromJSON FooBar where
parseJSON (Number n) = return (case maybeInt of
Just i -> (toEnum i)
Nothing -> ??)
where maybeInt = (Scientific.toBoundedInteger n)
parseJSON _ = mzero
但这并不能真正处理错误情况。最好的方法是什么?
答案 0 :(得分:1)
怎么样:
@Override
public void onDrawFrame(GL10 gl) {
if (isVideo) {
GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureId);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_REPEAT);
Log.d(TAG, GLES20.glGetError());
} else {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_REPEAT);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mImage, 0);
}
}
@Override //only called for video
synchronized public void onFrameAvailable(SurfaceTexture surface) {
mSurfaceTexture.updateTexImage();
mSurfaceTexture.getTransformMatrix(stMatrix);;
}
哪个会产生如下结果:
import Control.Monad
import Control.Monad.Fail as F
data FooBar = Foo | Bar deriving (Show, Enum, Bounded) -- note Bounded instance
instance FromJSON FooBar where
-- parseJSON is the one for Int, which internally uses the Scientific function
-- you used yourself
-- Control.Monad.Fail.MonadFail Parser, so safeToEnum may have type
-- safeToEnum :: Int -> Parser FooBar
-- (Control.Monad.<=<) is (.) but in the Kleisli category
-- (<=<) :: (b -> m c) -> (a -> m b) -> (a -> m c)
-- (.) :: (b -> c) -> (a -> b) -> (a -> c)
-- (f <=< g) x = do { x' <- g x; f x' }
-- (f . g) x = let x' = g x in f x'
-- it's always nice when something can just be a composition of smaller things
parseJSON = safeToEnum <=< parseJSON
-- using fail over mzero gives nicer error messages
-- (mzero = fail "mzero" for Parser, which is *very* informative)
-- this is a reusable function that can also produce Maybes, Eithers, etc.
-- depending on context, and works for lots of enumerations, since
-- many are Bounded (e.g. Bool, Char, etc.), and user-defined ones almost
-- always are.
safeToEnum :: (Enum a, Bounded a, MonadFail m) => Int -> m a
safeToEnum i = if i < min
then F.fail $ show i ++ " is less than the minimum, " ++ show min
else if i > max
then F.fail $ show i ++ " is greater than the maximum, " ++ show max
else return result
where min = fromEnum (minBound `asTypeOf` result)
max = fromEnum (maxBound `asTypeOf` result)
result = toEnum i -- hooray laziness
-- defining result and using it in min and max is safe, because
-- asTypeOf ignores the second argument; it's just there to clarify
-- to the type system which instance of Bounded we're talking about
-- it's not strictly necessary in GHC Haskell, because ScopedTypeVariables
-- would allow min = fromEnum (maxBound :: a)
-- but using asTypeOf keeps the language extension count down
答案 1 :(得分:0)
您可以使用您的解析器是forEach
(或更确切地说是MonadFail
)这一事实,因此可以使用Monad
方法使其失败。有了它,您的代码将如下所示:
fail