What does the double colon ( :: ) mean in Elm? - syntax

I'm new to Elm and I just came across this:
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
UrlChange location ->
( { model | history = location :: model.history }
, Cmd.none
)
Could someone tell me what the double colon does in line 5?

That's the cons operator. It adds an item to the front of a list.
1 :: [2,3] == [1,2,3]
1 :: [] == [1]
Documentation:
https://package.elm-lang.org/packages/elm/core/latest/List#::

Related

Haskell - Validate integer input from string using readMaybe

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)

Change widget model from parent in Elm

I am using the "compose" pattern in Elm.
In Main.elm, I am generating an initial seed for Random using the following:
type alias Model =
{ ...
, seed : Seed
}
initialModel : Model
initialModel =
{ ...
, seed = initialSeed 0
}
init : ( Model, Cmd Msg )
init =
( initialModel, generate InitializeSeed (int minInt maxInt) )
type Msg
= ...
| InitializeSeed Int
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
...
InitializeSeed value ->
( { model | seed = Random.initialSeed value }, Cmd.none )
which seems to work well for initializing the random number generator seed to a random starting value.
I have an "independent" widget that is used in the main application. I would like to pass the seed down to that widget on receipt of the InitializeSeed message and then retrieve the value as it changes in the child widget (using Random.step) so that I can then update other widgets' seeds as they need the generator.
How can I generate a message for the child widget from the update function in Main so that I can pass the seed down to the child? How can the child return the updated seed back to the parent?
UPDATE:
I figured out how to pass the seed down to the child widget, although I am not certain that this is best way.
The child code looks like this:
type alias Model =
{ ...
, seed : Seed
}
replaceSeed : Model -> Seed -> Model
replaceSeed model seed =
{ model | seed = seed }
and in the parent, I modified the update function like this:
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
...
InitializeSeed value ->
let
seed =
Random.initialSeed value
child_ =
Child.replaceSeed model.child seed
in
( { model
| seed = seed
, child = child_
}
, Cmd.none
)
I am still looking for a way to have the child return the updated seed.
While the top level update function in any Elm program must be
update : Msg -> Model -> (Model, Cmd Msg)
there are no limitations on the shape of any of its descendents. So nothing prevents you defining for your child
update : Seed -> Msg -> Model -> (Model, Cmd Msg, Seed)
or, if the child never returns any commands
update : Seed -> Msg -> Model -> (Model, Seed)
Maybe you have several things to pass down, including for example a parent message. Then you could go as far as
type alias Config msg =
{ seed : Seed
, someParentMessage : String -> msg
}
update : Config msg -> Msg -> Model -> (Model, Maybe (Cmd msg), Seed)
You need to wire these all up appropriately in Main of course, but the compiler will help with that.

How to fix this Purescript error: Could not match {...} with (...)?

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.

Records in PureScript

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.

How can I set an action to occur on a key release in xmonad?

How can I set an action to occur on a key release in xmonad?
I don't like menu bars and panels.
Instead of a panel like xmobar I want to have a full screen page of info, (time, currently selected window and workspace etc) appear when I hold down a key combo and then vanish when I let the keys go.
I could code the info page application myself.
I can set the info page to spawn on a key press.
I can not set anything to happen on a key release.
How can I set an action to occur on a key release?
I am considering extending xmonad myself to do this.
I hope I don't have to though because it'd be really annoying.
XMonad passes all received events, including KeyPress events, to the handleEventHook, so this code would be able to react on keyRelease events:
module KeyUp where
import Data.Monoid
import qualified Data.Map as M
import XMonad
import Control.Monad
keyUpEventHook :: Event -> X All
keyUpEventHook e = handle e >> return (All True)
keyUpKeys (XConf{ config = XConfig {XMonad.modMask = modMask} }) = M.fromList $
[ ((modMask, xK_v), io (print "Hi")) ]
handle :: Event -> X ()
handle (KeyEvent {ev_event_type = t, ev_state = m, ev_keycode = code})
| t == keyRelease = withDisplay $ \dpy -> do
s <- io $ keycodeToKeysym dpy code 0
mClean <- cleanMask m
ks <- asks keyUpKeys
userCodeDef () $ whenJust (M.lookup (mClean, s) ks) id
handle _ = return ()
You would use it like that in your xmonad.hs file:
handleEventHook = handleEventHook defaultConfig `mappend`
keyUpEventHook `mappend`
fullscreenEventHook
Unfortunately, this does not work yet: It will only react on KeyRelease events that have a corresponding entry in the regular keys configuration. This is due to grayKeys in XMonad.Main, grabbing only keys mentioned in keys. You can work-around this by defining a dummy action for every combination that you want to handle in KeyUp:
myKeys conf#(XConfig {XMonad.modMask = modMask}) = M.fromList $
...
, ((modMask , xK_v ), return ())
myStartupHook :: X ()
myStartupHook = do
XConf { display = dpy, theRoot = rootw } <- ask
myKeyCode <- io $ (keysymToKeycode dpy xK_Super_R)
io $ grabKey dpy (myKeyCode) anyModifier rootw True grabModeAsync grabModeAsync
spawn "~/ScriptsVcs/hideTint2.sh"
myHook :: Event -> X All
myHook e = do
case e of
ke#(KeyEvent _ _ _ _ _ _ _ _ _ _ _ _ _ _ _) -> do
if ev_keycode ke == 134
then if ev_state ke == 0
then do
-- key has been pressed
spawn "~/ScriptsVcs/showTint2.sh"
else do
spawn "~/ScriptsVcs/hideTint2.sh"
else pure ()
_ -> pure ()
pure $ All True
The above is an example. Do take note that a 'key release' could occur with a modifier key (ev_state).

Resources