I am trying to validate integer input from a string, I just need a boolean result if the input string correctly changes types to an integer. I tried this method from another question:
https://stackoverflow.com/a/30030649/3339668
This is the relevant code along with my imports:
import Data.Char
import Data.List
import Text.Read
checkValidInt :: String -> Bool
checkValidInt strInt
| readMaybe strInt :: Maybe Int == Nothing = False
| readMaybe strInt :: Maybe Int /= Nothing = True
However, I receive the following errors on loading the script:
Illegal operator ‘==’ in type ‘Maybe Int == Nothing’
Use TypeOperators to allow operators in types
main.hs:350:38:
Not in scope: type constructor or class ‘Nothing’
A data constructor of that name is in scope; did you mean DataKinds?
main.hs:351:35:
Illegal operator ‘/=’ in type ‘Maybe Int /= Nothing’
Use TypeOperators to allow operators in types
main.hs:351:38:
Not in scope: type constructor or class ‘Nothing’
A data constructor of that name is in scope; did you mean DataKinds?
So what kind of data type is Nothing? How do I check if Nothing is the result of readMaybe properly?
This is due to the fact that Haskell interprets your
readMaybe strInt :: (Maybe Int == Nothing = False)
as:
readMaybe strInt :: (Maybe Int == Nothing = False)
It can make no sense out of this. So you can help Haskell by using some brackets:
(readMaybe strInt :: Maybe Int) == Nothing = False
You also better do not repeat the condition, but use otherwise, since if you repeat it, the program will - unless optimized - do the parsing twice, so:
checkValidInt :: String -> Bool
checkValidInt strInt
| (readMaybe strInt :: Maybe Int) == Nothing = False
| otherwise = True
Since you check for a condition such that the result is True if the condition is False, and vice versa, it is no use to use guards, we can write it as:
checkValidInt :: String -> Bool
checkValidInt strInt = Nothing /= (readMaybe strInt :: Maybe Int)
Or we can use a pattern guard, this can be used in case we can not perform equality checks on the type of value that is wrapped in the Maybe, so:
checkValidInt :: String -> Bool
checkValidInt strInt | Just _ <- (readMaybe strInt :: Maybe Int) = True
| otherwise = False
Or we can use the isJust :: Maybe a -> Bool function:
checkValidInt :: String -> Bool
checkValidInt strInt = isJust (readMaybe strInt :: Maybe Int)
I just need a boolean result
Probably not. You need a Maybe Int to pattern match on, and readMaybe already gives you that without any further processing.
Instead of this
if checkValidInt s -- try reading an Int, but throw it away
then foo (read s) -- now really read an Int and use it
else bar -- fall back
you do this
case readMaybe s of -- try reading an Int
Just i -> foo i -- use it
Nothing -> bar -- fall back
Normally an explicit type annotation should not be needed, if foo is of the right type; but see below.
If you, for some unfathomable reason, really need checkValidInt, you base it on the above pattern
case (readMaybe s) :: Maybe Int of
Just _ -> True
Nothing -> False
As noted in another answer, the maybe function abstracts this pattern match away, but I would recommend using explicit pattern matches whenever you can as an exercise, to get the hang of it.
You could rewrite this as
import Data.Char
import Data.List
import Text.Read
checkValidInt :: String -> Bool
checkValidInt strInt =
case (readMaybe strInt :: Maybe Int) of
Nothing -> False
Just _ -> True
The algorithm you need here has already been abstracted behind the maybe function:
checkValidInt :: String -> Bool
checkValidInt = maybe False (const True) . (readMaybe :: String -> Maybe Int)
If readMaybe returns Nothing, then maybe returns False. Otherwise, it just applies const True to the resulting Just value, which returns True without caring about just what is wrapped by Just. Note that you are specializing the type of readMaybe itself, not the type of its return value.
Or, even simpler with an import,
import Data.Maybe
checkValidInt :: String -> Bool
checkValidInt = isJust . (readMaybe :: String -> Maybe Int)
Related
I have a Haskell application which uses optparse-applicative library for CLI arguments parsing. My data type for CLI arguments contains FilePaths (both files and directories), Doubles and etc. optparse-applicative can handle parse errors but I want to ensure that some files and some directories exist (or don't exist), numbers are >= 0 and etc.
What can be done is an implementation of a bunch of helper functions like these ones:
exitIfM :: IO Bool -> Text -> IO ()
exitIfM predicateM errorMessage = whenM predicateM $ putTextLn errorMessage >> exitFailure
exitIfNotM :: IO Bool -> Text -> IO ()
exitIfNotM predicateM errorMessage = unlessM predicateM $ putTextLn errorMessage >> exitFailure
And then I use it like this:
body :: Options -> IO ()
body (Options path1 path2 path3 count) = do
exitIfNotM (doesFileExist path1) ("File " <> (toText ledgerPath) <> " does not exist")
exitIfNotM (doesDirectoryExist path2) ("Directory " <> (toText skKeysPath) <> " does not exist")
exitIfM (doesFileExist path3) ("File " <> (toText nodeExe) <> " already exist")
exitIf (count <= 0) ("--counter should be positive")
This looks too ad-hoc and ugly to me. Also, I need similar functionality for almost every application I write. Are there some idiomatic ways to deal with this sort of programming pattern when I want to do a bunch of checks before actually doing something with data type? The less boilerplate involved the better it is :)
Instead of validating the options record after it has been constructed, perhaps we could use applicative functor composition to combine argument parsing and validation:
import Control.Monad
import Data.Functor.Compose
import Control.Lens ((<&>)) -- flipped fmap
import Control.Applicative.Lift (runErrors,failure) -- form transformers
import qualified Options.Applicative as O
import System.Directory -- from directory
data Options = Options { path :: FilePath, count :: Int } deriving Show
main :: IO ()
main = do
let pathOption = Compose (Compose (O.argument O.str (O.metavar "FILE") <&> \file ->
do exists <- doesPathExist file
pure $ if exists
then pure file
else failure ["Could not find file."]))
countOption = Compose (Compose (O.argument O.auto (O.metavar "INT") <&> \i ->
do pure $ if i < 10
then pure i
else failure ["Incorrect number."]))
Compose (Compose parsy) = Options <$> pathOption <*> countOption
io <- O.execParser $ O.info parsy mempty
errs <- io
case runErrors errs of
Left msgs -> print msgs
Right r -> print r
The composed parser has type Compose (Compose Parser IO) (Errors [String]) Options. The IO layer is for performing file existence checks, while Errors is a validation-like Applicative from transformers that accumulates error messages. Running the parser produces an IO action that, when run, produces an Errors [String] Options value.
The code is a bit verbose but those argument parsers could be packed in a library and reused.
Some examples form the repl:
Λ :main "/tmp" 2
Options {path = "/tmp", count = 2}
Λ :main "/tmpx" 2
["Could not find file."]
Λ :main "/tmpx" 22
["Could not find file.","Incorrect number."]
I have a state for a halogen component including a lens like this:
import Optic.Core (Lens', lens)
type State =
{ userName :: String
, password :: String
, formError :: String
}
_userName :: Lens' State String
_userName = lens _.userName (\r str -> r { userName = str })
And I want to modify the state in the eval function of the same component like this:
eval :: forall eff.
Query ~> ParentDSL State Query UserNameField.Query Slot Void (Aff (console :: CONSOLE , ajax :: AJAX | eff))
eval = case _ of
HandleInput userName next -> do
-- this code causes trouble:
_userName .= userName
-- while this code works:
-- modify (set _userName userName)
pure next
However, I get the error message:
Could not match type
{ userName :: String
, password :: String
, formError :: String
}
with type
( userName :: String
, password :: String
, formError :: String
)
while trying to match type t3
{ userName :: String
, password :: String
, formError :: String
}
with type t2
while checking that expression _userName
has type (t0 -> t1) -> t2 -> t2
in value declaration eval
where t1 is an unknown type
t0 is an unknown type
t2 is an unknown type
t3 is an unknown type
[TypesDoNotUnify]
Note the difference between { and ( (took me a while). I don't even know what the latter type actually means and I have no clue why this error is introduced by a MonadState-based lense.
Mystery solved: I unintentionally mixed two packages
purescript-lens and purescript-profunctor-lenses. My lenses came from the former and the assign function (.=) is only present in the latter, which was installed apparently as some implicit subdependency.
I am trying to check if my set of chars in elm contains only valid chars. If a char is found that is invalid, I return those chars, separated by a comma. What I currently have tries to convert the string to a list of chars, then that list to a set of chars. Then diffs the set with a set of valid chars, not sure where to go after that, I have not written much in Elm before. If no diffs are found then return nothing.
validChars : Set.Set Char
validChars =
Set.fromList <| String.toList " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
validString : String -> Maybe String
validString x =
let
list =
String.toList x
set1 =
Set.fromList list
diffs=
Set.diff set1 validChars
if Set.isEmpty diffs == True
Nothing
The if statement doesn't work in Elms online compiler, it says it is looking for "in"
Your code has a few things wrong with it, here's a version that compiles.
import Set
validChars : Set.Set Char
validChars = Set.fromList <| String.toList " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
validString : String -> Maybe String
validString string =
let
diff =
Set.diff validChars <| Set.fromList <| String.toList string
in
if not <| Set.isEmpty diff then
Just string
else
Nothing
Basically when it said it was looking for in, it wasn't wrong, in is a necessary part of a function when you use let statements.
I don't quite understand why this works:
module Records where
type Element e = { element :: String, label :: String | e }
type Sel = ( value :: Number, values :: [Number] )
type Select = Element Sel
while this says Cannot unify # * with *.
module Records where
type Element e = { element :: String, label :: String | e }
type Sel = { value :: Number, values :: [Number] }
type Select = Element Sel
(Note the '()' around the right hand side of Sel instead of the '{}'.)
I've read here https://leanpub.com/purescript/read#leanpub-auto-objects-and-rows that forall r. { firstName :: String, lastName :: String | r } desugars to
forall r. Object (firstName :: String, lastName :: String | r)
I'm still a bit confused, why you can't use the record-sugar for extending records.
The Object type constructor is parameterized by a row of types. In kind notation, Object has kind # * -> *. That is, it takes a row of types to a type.
( value :: Number, values :: [Number] ) denotes a row of types (something of kind # *), so it can be passed to Object to construct a type, namely
Object ( value :: Number, values :: [Number] )
Note that { ... } is just syntactic sugar for the Object type constructor, so this is the same as
{ value :: Number, values :: [Number] }
Both have kind *, so it doesn't make sense to pass this thing as an argument to Element, since the type variable e in Element has kind # *.
Put another way, Element Sel in your second example unrolls to
{ element :: String, label :: String | { value :: Number, values :: [Number] } }
which desugars to
Object (element :: String, label :: String | Object (value :: Number, values :: [Number]) )
which fails to kind-check due to the thing of kind * in the tail of the outer row.
I'm trying to get the location of Window's Local AppData folder in a version-agnostic manner using Haskell, and I'm having a bit of trouble doing so. I've tried using the System.Win32.Registry library, and I was able to get the code below (after some trial and error), but I wasn't able to figure out how to use the regQueryValueEx or any other function to get the value I need.
import System.Win32.Types
import System.Win32.Registry
userShellFolders :: IO HKEY
userShellFolders = regOpenKeyEx hKEY_CURRENT_USER "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\" kEY_QUERY_VALUE
I also tried looking at the source code for the getAppUserDataDirectory function in the System.Directory module, but that didn't help me either.
Maybe there's an easier way to do this that I'm just missing.
If you want portability, you shouldn't access registry directly. There is an API function
to get special folders: SHGetFolderPath. You can call it thus:
{-# LANGUAGE ForeignFunctionInterface #-}
import System.Win32.Types
import Graphics.Win32.GDI.Types
import Foreign.C.String
import Foreign.Marshal.Array
foreign import stdcall unsafe "SHGetFolderPathW"
cSHGetFolderPathW :: HWND -> INT -> HANDLE -> DWORD -> CWString -> IO LONG
maxPath = 260
cSIDL_LOCAL_APPDATA = 0x001c -- //see file ShlObj.h in MS Platform SDK for other CSIDL constants
getShellFolder :: INT -> IO String
getShellFolder csidl = allocaArray0 maxPath $ \path -> do
cSHGetFolderPathW nullHANDLE csidl nullHANDLE 0 path
peekCWString path
main = getShellFolder cSIDL_LOCAL_APPDATA >>= putStrLn
To read the values from the registry in a useful format quite some code is necessary to convert between Haskell and C types. And that the values in question are usually of type REG_EXPAND_SZ also doesn't help. So it's not pretty, but this works for me:
{-# LANGUAGE ForeignFunctionInterface #-}
import System.Win32.Types
import System.Win32.Registry
import Foreign.Ptr (castPtr)
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.C.String (peekCWString, withCWString)
import Control.Exception (bracket, throwIO)
-- // parse a string from a registry value of certain type
parseRegString :: RegValueType -> LPBYTE -> IO String
parseRegString ty mem
| ty == rEG_SZ = peekCWString (castPtr mem)
| ty == rEG_EXPAND_SZ = peekCWString (castPtr mem) >>=
expandEnvironmentStrings
| otherwise = ioError (userError "Invalid registry value type")
-- // FFI import of the ExpandEnvironmentStrings function needed
-- // to make use of the registry values
expandEnvironmentStrings :: String -> IO String
expandEnvironmentStrings toexpand =
withCWString toexpand $ \input ->
allocaBytes 512 $ \output ->
do c_ExpandEnvironmentStrings input output 256
peekCWString output
foreign import stdcall unsafe "windows.h ExpandEnvironmentStringsW"
c_ExpandEnvironmentStrings :: LPCTSTR -> LPTSTR -> DWORD -> IO DWORD
-- // open the registry key
userShellFolders :: IO HKEY
userShellFolders = regOpenKeyEx hKEY_CURRENT_USER
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"
kEY_QUERY_VALUE
-- // read the actual value
localAppData :: IO String
localAppData =
bracket userShellFolders regCloseKey $ \usfkey ->
allocaBytes 512 $ \mem ->
do ty <- regQueryValueEx usfkey "Local AppData" mem 512
parseRegString ty mem
main = localAppData >>= print
I'm not sure if all the error cases are handled correctly (like if the passed buffer was to small), so you might want to check the windows docs to see what happens in these cases.