Elm: How can I find out the type of an Elm expression or a subexpression in elm-repl? - elm

How can I find out the type of an Elm expression or a subexpression in elm-repl ?
Haskell's :type or :t equivalent in Elm REPL?

The Elm REPL automatically prints the type of whatever you enter. For example:
> "foo"
"foo" : String
> f = \a b c -> (a + 1, b ++ "!", c || False)
<function> : number -> String -> Bool -> ( number, String, Bool )
> f
<function> : number -> String -> Bool -> ( number, String, Bool )
> f2 a b c = (a + 1, b ++ "!", c || False)
<function> : number -> String -> Bool -> ( number, String, Bool )
As #amalloy points out, without an equivalent to GHCi's :type command, Elm REPL (as of 0.18) forces evaluation of an expression prior to showing you the type, which may be undesirable for expensive function calls. In its current version, there is no way around this.

Related

Trying to bring implicit argument into scope on the left side of a definition in Idris results in "is f applied to too many arguments" error

The function applyRule is supposed to extract the implicit argument n that is used in another arguments it gets, of type VVect.
data IVect : Vect n ix -> (ix -> Type) -> Type where -- n is here
Nil : IVect Nil b
(::) : b i -> IVect is b -> IVect (i :: is) b
VVect : Vect n Nat -> Type -> Type -- also here
VVect is a = IVect is (flip Vect a)
-- just for completeness
data Expression = Sigma Nat Expression
applyRule : (signals : VVect is Double) ->
(params : List Double) ->
(sigmas : List Double) ->
(rule : Expression) ->
Double
applyRule {n} signals params sigmas (Sigma k expr1) = cast n
Without referring to {n}, the code type-checks (if cast n is changed to some valid double). Adding it in, however, results in the following error:
When checking left hand side of applyRule:
Type mismatch between
Double (Type of applyRule signals params sigmas rule)
and
_ -> _ (Is applyRule signals
params
sigmas
rule applied to too many arguments?)
This doesn't seem to make sense to me, because I'm not pattern-matching on any parameter that could have a dependency on n, so I thought that simply putting it in curly braces would bring it into scope.
You can only bring n into scope if it is defined somewhere (e.g. as a variable in the arguments). Otherwise it would be hard to figure out where the n comes from – at least for a human.
applyRule : {is : Vect n Nat} ->
(signals : VVect is Double) ->
(params : List Double) ->
(sigmas : List Double) ->
(rule : Expression) ->
Double
applyRule {n} signals params sigmas (Sigma k expr1) = cast n

How can I create a function that only accepts a subset of constructors of a type?

Let's say I have a type like this:
data Foo = Bar String | Baz | Qux String
I want to have a function like this:
get : Foo -> String
get (Bar s) = s
get (Qux s) = s
As written, this compiles, but it's not total, as there are missing cases; in other words, get Baz is treated like a hole rather than as an expression that doesn't typecheck.
I want to replace that Foo in the type signature of get with something that specifies that the value must be either a Bar or a Qux. How can I express this subset of the Foo type?
You could also mix the two approaches (by Kim Stiebel and Anton Trunov) and construct a helper data type. The type OnlyBarAndQux can only be constructed with values of Bar and Qux. For idris it is then possible to automatically infer a proof if this is the case when invoking get:
module FooMe
data Foo = Bar String | Baz | Qux String
data OnlyBarAndQux: Foo -> Type where
BarEy: OnlyBarAndQux (Bar s)
QuxEx: OnlyBarAndQux (Qux s)
||| get a string from a Bar or Qux
total
get: (f: Foo) -> {auto prf : OnlyBarAndQux f} -> String
get (Bar s) {prf = BarEy} = s
get (Qux s) {prf = QuxEx} = s
-- Tests
test1: get $ Bar "hello" = "hello"
test1 = Refl
test2: get $ Qux "hello" = "hello"
test2 = Refl
-- does not compile
-- test3: get $ Baz = "hello"
I'd follow the approach taken in the std library for List head, for example. This is basically what Markus wrote plus using Dec for witnessing that a Foo being not Baz is decidable:
%default total
data Foo = Bar String | Baz | Qux String
data NotBaz : Foo -> Type where
IsBar: NotBaz(Bar z)
IsQux: NotBaz(Qux z)
Uninhabited (NotBaz Baz) where
uninhabited _ impossible
notBaz : (f : Foo) -> Dec (NotBaz f)
notBaz Baz = No absurd
notBaz (Bar s) = Yes IsBar
notBaz (Qux s) = Yes IsQux
get: (f : Foo) -> {auto ok : NotBaz f} -> String
get (Bar s) { ok = IsBar } = s
get (Qux s) { ok = IsQux } = s
s: String
s = get (Bar "bar")
Some comments about this:
Do not use just a predicate a -> Bool for working with a subset type of a; create a view like NotBaz above. See the Idris tutorial on views, this post, and this answer for context.
Use Dec whenever possible instead of equality. Intutitively, you will be able to use Dec for predicates on types for which you can explicitly decide the truth of the predicate: see notBaz above.
auto implicit arguments can help reducing the visual/cognitive clutter at usage site
There is more than one way to do this, but the easiest is probably to make Foo a type constructor that takes a parameter indicating whether it's a Foo with a String in it or not. In this example I have used a Bool as the parameter:
%default total
data Foo : Bool -> Type where
Bar : String -> Foo True -- a Foo constructed with Bar will have type Foo True
Baz : Foo False -- and a Foo constructed with Baz will have type Foo False
Qux : String -> Foo True
get : Foo True -> String
get (Bar s) = s
get (Qux s) = s
I'd go with Kim Stebel's answer (if changing Foo is an option, as observed by #Eduardo Pareja Tobes), but I'd like to show another way. You can use a subset type, which is the same thing as dependent pair:
total
get : (f ** Not (f = Baz)) -> String
get (f ** pf) with (f)
get (f ** _) | (Bar s) = s -- this is as before
get (f ** contra) | Baz = void $ contra Refl -- a contradictory case
get (f ** _) | (Qux s) = s -- this is as before
(f ** Not (f = Baz)) can be translated as "some f of type Foo, but not Baz".
To call get you need to provide a dependent pair of an element of type Foo and a proof that it is not equal to Baz, like so:
s : String
s = get (Bar "bar" ** \Refl impossible)

String to int conversion using toInt function

I am trying to convert a string to integer using String.toInt. However, when I want to bind the result to a variable and then do some simple math with it I get this error:
Function add is expecting the 2nd argument to be:
Int
But it is:
Result String Int
How can I just extract the integer part of the result?
Here's how to supply the conversion with a default value in case the parsing fails.
String.toInt "5" |> Result.toMaybe |> Maybe.withDefault 0
toInt can fail in parsing. You need to check it using a case statement:
case toInt str of
Err msg -> ... -- do something with the error message
Ok val -> ... -- val is an Int which you can add
More about Result here
The integer can also be pulled out using
Result.withDefault 0 (String.toInt "2")
You can read more about it here
According to the Elm String reference documentation, if you are extracting a number from some raw user input, you will typically want to use Result.withDefault to handle bad data in case parsing fails. You can chain this operation using pipes for cleaner code:
String.toInt "5" |> Result.withDefault 0
Maybe.withDefault 0 (String.toInt "42")
Use map:
answer = Result.map2 (+) (String.toInt "1") (String.toInt "2")
map2:
Apply a function to two results, if both results are Ok. If not, the
first argument which is an Err will propagate through.
to have the add result as a string
resultAsString r =
case r of
Err msg -> msg
Ok value -> toString value
resultAsString answer
to make things easier you can create an addStrings function:
addStrings : String -> String -> Result String Int
addStrings a b =
Result.map2 (+) (String.toInt a) (String.toInt b)
You can even get away with the Result type altogether:
addStrings : String -> String -> String
addStrings a b =
let
r =
Result.map2 (+) (String.toInt a) (String.toInt b)
in
case r of
Err msg ->
msg
Ok value ->
toString value
Testing
import Html exposing (Html, text)
main : Html msg
main =
text (addStrings "1" "2")
output 3
The withDefault method forces you to define a value that can be used for calculations but it is not always possible to establish a value that is significant for errors. Most often you need all the possible values, and default is not fit. Here I provide a result type check function you can use to decide if you use or not the converted value:
isErrorResult r =
case r of
Err msg ->
True
Ok value ->
False
You can use it like this:
r = String.toInt "20b"
if isErrorResult r then
-- not a valid Interger, abort or whatever
else
-- a good integer, extract it
a = Result.withDefault 0 r
-- and make good use of it
the default value (0 in this case) passed to withDefault is meaningless, because we made sure that r is not an Err.
You can do this as below.
---- Elm 0.19.0 ----------------------------------------------------------------
Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help, imports, etc.
--------------------------------------------------------------------------------
> parseInt string = String.toInt string
<function> : String -> Maybe Int
> resultParseInt string = \
| Result.fromMaybe ("error parsing string: " ++ string) (parseInt string)
<function> : String -> Result String Int
> resultParseInt "12"
Ok 12 : Result String Int
> resultParseInt "12ll"
Err ("error parsing string: 12ll") : Result String Int
>
I have changed guys answers a bit, since it appears to be of type Maybe
isErrorResult : String -> Bool
isErrorResult r =
case String.toInt r of
Nothing -> True
Just value -> False

Propositions vs. boolean values for input validation

I have the following code:
doSomething : (s : String) -> (not (s == "") = True) -> String
doSomething s = ?doSomething
validate : String -> String
validate s = case (not (s == "")) of
False => s
True => doSomething s
After checking the input is not empty I would like to pass it to a function which accepts only validated input (not empty Strings).
As far as I understand the validation is taking place during runtime
but the types are calculated during compile time - thats way it doesn't work. Is there any workaround?
Also while playing with the code I noticed:
:t (("la" == "") == True)
"la" == "" == True : Bool
But
:t (("la" == "") = True)
"la" == "" = True : Type
Why the types are different?
This isn't about runtime vs. compile-time, since you are writing two branches in validate that take care, statically, of both the empty and the non-empty input cases; at runtime you merely choose between the two.
Your problem is Boolean blindness: if you have a value of type Bool, it is just that, a single bit that could have gone either way. This is what == gives you.
= on the other hand is for propositional equality: the only constructor of the type(-as-proposition) a = b is Refl : a = a, so by pattern-matching on a value of type a = b, you learn that a and b are truly equal.
I was able to get your example working by passing the non-equality as a proposition to doSomething:
doSomething : (s : String) -> Not (s = "") -> String
doSomething "" wtf = void $ wtf Refl
doSomething s nonEmpty = ?doSomething
validate : String -> String
validate "" = ""
validate s = doSomething s nonEmpty
where
nonEmpty : Not (s = "")
nonEmpty Refl impossible
As far as I understand the validation is taking place during runtime
but the types are calculated during compile time - thats way it
doesn't work.
That's not correct. It doesn't work because
We need the with form to perform dependent pattern matching, i. e. perform substitution and refinement on the context based on information gained from specific data constructors.
Even if we use with here, not (s == "") isn't anywhere in the context when we do the pattern match, therefore there's nothing to rewrite (in the context), and we can't demonstrate the not (s == "") = True equality later when we'd like to call doSomething.
We can use a wrapper data type here that lets us save a proof that a specific pattern equals the original expression we matched on:
doSomething : (s : String) -> (not (s == "") = True) -> String
doSomething s = ?doSomething
data Inspect : a -> Type where
Match : {A : Type} -> {x : A} -> (y : A) -> x = y -> Inspect x
inspect : {A : Type} -> (x : A) -> Inspect x
inspect x = Match x Refl
validate : String -> String
validate s with (inspect (not (s == "")))
| Match True p = doSomething s p
| Match False p = s

GHC rejects ST monad code as unable to unify type variables?

I wrote the following function:
(.>=.) :: Num a => STRef s a -> a -> Bool
r .>=. x = runST $ do
v <- readSTRef r
return $ v >= x
but when I tried to compile I got the following error:
Could not deduce (s ~ s1)
from the context (Num a)
bound by the type signature for
.>=. :: Num a => STRef s a -> a -> Bool
at test.hs:(27,1)-(29,16)
`s' is a rigid type variable bound by
the type signature for .>=. :: Num a => STRef s a -> a -> Bool
at test.hs:27:1
`s1' is a rigid type variable bound by
a type expected by the context: ST s1 Bool at test.hs:27:12
Expected type: STRef s1 a
Actual type: STRef s a
In the first argument of `readSTRef', namely `r'
In a stmt of a 'do' expression: v <- readSTRef r
Can anyone help?
This is exactly as intended. An STRef is only valid in one run of runST. And you try to put an external STRef into a new run of runST. That is not valid. That would allow arbitrary side-effects in pure code.
So, what you try is impossible to achieve. By design!
You need to stay within the ST context:
(.>=.) :: Ord a => STRef s a -> a -> ST s Bool
r .>=. x = do
v <- readSTRef r
return $ v >= x
(And as hammar points out, to use >= you need the Ord typeclass, which Num doesn't provide.)