I have a Haskell function eval :: WExp -> Memory -> WValue
with a bunch of different instances of itself for different cases. For now, knowledge about WExp
, Memory
, and WValue
is not relevant. My problem is that, for a specific instance of eval
, I am using a lookup
function, which takes the parameter of eval
(a string in this case) searches a list of key-value pairs for that string. Note that this lookup
function is not the one included in the Prelude; it is self-defined within the .hs file. If the string is found, the value associated with it is returned, but if it is not found, Nothing
is returned. Because of the Nothing
case, the type of lookup
is actually Maybe a
, where a
would be a WValue
in this case. Because eval
would return a Maybe WValue
, the compiler obviously complains that the type is not WValue
.
I thought that there might be some kind of general method to extract the a
value from any function that returns Maybe a
.
The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a ), or it is empty (represented as Nothing ). Using Maybe is a good way to deal with errors or exceptional cases without resorting to drastic measures such as error .
The /= operator means "is not equal".
The == is an operator for comparing if two things are equal. It is quite normal haskell function with type "Eq a => a -> a -> Bool". The type tells that it works on every type of a value that implements Eq typeclass, so it is kind of overloaded.
return is actually just a simple function in Haskell. It does not return something. It wraps a value into a monad. Looks like return is an overloaded function.
do
input <- getUserInput
result <- lookup input structure
case result of
Just a -> putStrLn $ "I'm so happy you chose "++show a++"."
Nothing -> putStrLn $ "So sorry; "++input++" is not a valid option."
do
input <- getUserInput
result <- lookup input structure
case result of
Just a -> putStrLn $ "I'm so happy you chose "++show a++"."
Nothing -> error $ input ++ " is not a valid option."
This is bad because your program just goes splat if the user input is wrong.
There is a function called fromJust
that attempts to pull a value out of a Maybe
and throws an error if it finds Nothing
. It looks like
fromJust :: Maybe a -> a
fromJust (Just a) = a
fromJust Nothing = error "Oops, you goofed up, fool."
This makes it hard to see what went wrong.
But if you want to play with fire, you can try it just for fun. This will attempt to get a value out of a Maybe
and crash real hard if it finds Nothing
. By "crash real hard" I mean you'll get a segmentation fault if you're lucky, and you'll publish your private keys on the web if you're not.
{-# LANGUAGE GADTs, DataKinds, KindSignatures #-}
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
module Unsafe.FromJust (unsafeFromJust) where
-- Clear sign of bad news
import Unsafe.Coerce (unsafeCoerce)
-- This creates a "closed kind" with types
-- 'JustType and 'NothingType. You could just
-- define datatypes called JustType and NothingType,
-- but this makes the intent clearer.
data MaybeType = JustType | NothingType
data M (t::MaybeType) a where
-- The order of these constructors must not
-- be changed, because this type must look,
-- at runtime, exactly like a Maybe
N :: M 'NothingType a
J :: a -> M 'JustType a
-- A safe sort of fromJust for M.
fromJ :: M 'JustType a -> a
fromJ (J a) = a
-- Really, seriously unsafe.
unsafeFromJust :: Maybe a -> a
unsafeFromJust m = fromJ (unsafeCoerce m)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With