Update : I noticed that there was a problem in the design of my code. The overall structure of my code has changed so much that any answer to this question would be more or less irrelevant to its current state. But SO says it's better not to delete an answered question, so I am keeping the question.
The problem with my code was that typeclasses were too generic for what I wanted to do. Now I concentrate on writting functions like
makeModelId :: String -> Either StringValueError ModelId
Then extend that with something like:
makeModelIdM :: (Monad m) => String -> m (Either StringValueError ModelId)
makeModelIdM astr = do
idstr <- astr
return (makeModelId idstr)
I am not sure if it is the best approach though..
I know that there are lots of similar questions to this like this or this or this , and as far I understood what I want to do can be achieved with HUnit
. But I can't seem to find the exact way of doing it.
I basically have a setter typeclass which is
class StringLike2Primitive model where
fromString :: String -> model
fromText :: Text -> model
fromText aText = fromString (unpack aText)
class (StringLike2Primitive model) => StringLike2PrimitiveM model where
fromStringM :: (MonadPlus m) => String -> m model
fromTextM :: (MonadPlus m) => Text -> m model
fromStringM astr = return (fromString astr)
fromTextM aText = fromStringM (unpack aText)
And I have couple of data types which implement these typeclasses, for example:
instance StringLike2Primitive ModelId where
fromString = StringIdCons
instance StringLike2PrimitiveM ModelId where
fromStringM aStr
| null aStr = fail "empty string is not allowed as id"
| not (isAlphaNumStr aStr) = fail
"Only ascii alphanumeric strings are allowed"
| not (isAsciiStr aStr) = fail
"Only ascii alphanumeric strings are allowed"
I am not sure how can I test fromStringM
function against guarded values in a unit test environment, and I think my approach to error handling is problematic. Any tips would be appreciated.
(This is more of a comment, but might be an answer as well.)
Are you sure you need a second type class? The definition of fromStringM
doesn't rely on the StringLike2Primitive
instance so much as it simply wraps it.
fromStringM :: (Monad m, StringLike2Primitive a) => String -> m a
fromStringM a
| null a = fail "empty string is not allowed"
| not (isAlphaNumStr aStr) = fail "Only ascii alphanumeric strings are allowed"
| not (isAsciiStr aStr) = fail "Only ascii strings are allowed"
| otherwise = return $ fromString a
and likewise for fromText
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.