Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elm - Check the Type of a value

Does a function exists that checks the Type of a variable in an Elm? For example (repl):

numberTwo = 2
.....
returnType numberTwo
"number" : String

The motivation for this is that when you are using Signal.map[n] the situation usually arises that not all of the arguments to the function to be applied are Signals - they then usually have to be 'promoted' to Signals using Signal.constant - if I could check the type of such arguments, I could create a function Signal.allSigMap[n] that would turn such arguments into Signals automatically.

So

Signal.map2 grandFatherClock clockSignalElement (Signal.constant cabinetElement)

becomes

Signal.allSigMap2 grandFatherClock clockSignalElement cabinetElement

Could be bad practice though. Please let me know.

like image 330
category Avatar asked Apr 10 '16 20:04

category


People also ask

Are there any special type variables like number in Elm?

There are very few special type variables like number in Elm. Like List, the type of an array is Array.Array followed by the type of values the array contains. Types that aren’t pre-loaded into the repl are prefixed with the name of the module where they are defined.

How can Elm help us detect errors in our code?

Elm can help us detect errors in our code by validating the type annotation against the actual code. Let’s say we want to write a function that adds two numbers. After some experimentation, we’ve figured out that the function’s type annotation should be: Add the following function definition right above main in Playground.elm.

What is the difference between 1 and 2 in Elm?

After all, 1 and 2 both have the same type: number. But remember, in Elm there are two types of numbers: Float and Int. Because the type (number, number) uses exactly the same type variable, twice, that would mean our tuple would have to have exactly the same type twice — either two Int s or two Float s.

How to use list in Elm?

The List, Tuples and Record data structures can be used to store a collection of values. This chapter discusses how to use List in Elm. A List is a collection of homogeneous values. The values in a list must all be of the same data type. Consider the following limitations while using variables to store values − Variables are scalar in nature.


4 Answers

I'll respond first to your intention to use returnType as a way of promoting types as necessary to Signal. That would entail that returnType or some other function along the way actually return a type rather than a String since there's no other way to make the type checker happy.

Such a function does not exist and cannot exist within Elm as it stands today. What you're asking for is something that can inspect the type of a value compile time and then run a function on that type.

To see why this is radically different from anything that currently exists in Elm, let's assume such a function exists.

returnType : a -> ?

We're immediately confronted with the first question of what exactly is the type of returnType. Let's handwave this and say we have a type for all types called Type (which has its own set of logical problems we'll leave aside).

returnType : a -> Type

How do we actually use this function? Presumably it'll be able to go in the type signature since it's returning a type.

 x : returnType 5

Now that is a type signature completely different from everything else in Elm. There's a numeric literal (and a function)! All of a sudden you can start to write things like this.

y = 5

x : returnType y
x = 6

That is way beyond what Elm's type system can do. That sort of (exciting and powerful) type level and value level mixing is known as dependent typing and no mainstream fully dependently typed languages exist; the closest things to mainstream are probably Coq, Agda, Idris, and ATS which are all fairly obscure.

As for the question as literally stated of having a function returnType : a -> String that prints out a string representing the type of a value, that's also not possible in Elm, although for other reasons. Such a function (which is something whose application occurs at runtime) must be able to reconstruct type information about a runtime value, but runtime values of Elm are just Javascript values; they've been stripped of their Elm types. You'll have to either reconstruct the original Elm type from the Javascript value (not always possible as different types can end up as the same Javascript value) or have special compiler support.

In the case of the Elm REPL, the latter is chosen. The whole REPL is written in Haskell and takes of advantage of how Elm types are implemented in the Haskell runtime.

like image 159
badcook Avatar answered Sep 22 '22 12:09

badcook


This is not possible (and not desirable, I would argue) due to Type Erasure (https://en.wikipedia.org/wiki/Type_erasure). Because everything in elm must be well typed, the compiler can verify all the types line up at compile time. Once that is done, it can safely remove all type information from the compiled code that actually gets run. This actually makes the code more efficient, as at runtime no type information (or runtime type checks, like you may be familiar with in typical javascript code) needs to be carried around with all your values.

I believe it's unlikely runtime type introspection would ever be added to languages like elm. Needing to check a type at runtime is a codesmell for poorly designed code.

like image 26
throughnothing Avatar answered Sep 21 '22 12:09

throughnothing


I also wondered why no instanceOf or typeOf in Elm. Then going through docs thoroughly for deeper understanding of FRP it became clear! You should know the shape of your data at all times. In order to do so using case...of pattern with Elms Tagged Unions you should be able to access your desired values by filtering your known types. Caveat, all branches of case...of must be of the same type, but that doesn't preclude you from using a tuple with superset of of all your known types with dummy sentinel values to allow you access your desired type.

See code below for illustration:

Assumptions:

1.Your desired types are tagged when used

2.Using sentinel values

import Html exposing (text)



    type Input = Nothing | ILetter String | INumber Int | IFloat Float

inputs: List (Input)
inputs = [ Nothing, IFloat 8.34, ILetter "A", INumber 5, INumber -1, IFloat -12.0, ILetter "123!"]


--
doSomething: Input -> (String, Int, Float)
doSomething myInput =
   case myInput of
    Nothing ->
       ("not here!", -69, 69.0)

    ILetter string ->
            if string /= "DarnString" then
             (string, 0, 0) 
            else
             ("DarnString", -1, -1.0)

    INumber int ->
            if int > 0 then
             ("GoodInt" , int, toFloat int)      
            else
             ("DarnInt" , int, toFloat int)

    IFloat float ->
            if float < 0 then 
             ("Goodfloat", truncate float, float)  
            else
             ("Darnfloat", truncate float, float)




-- I am only interested in using strings
myStringFilter (mString, mInt, mFloat) =
            if mString == "DarnString" || mString == "Darnfloat" ||  mFloat < 0  || mString == "DarnInt" || mInt > 0 then
              "We are not the String(s) you were looking for!"
            else
               mString

myFloatFilter (mString, mInt, mFloat) =
            if  mString == "DarnString" || mString == "Darnfloat" || mString == "DarnInt" then
              696969696.696969696969
            else                 
                mFloat

myIntFilter (mString, mInt, mFloat) =
            if  mString == "DarnString" || mString == "Darnfloat" || mString == "DarnInt" then
              -696969696
            else                 
                mInt               

main =
     text (toString <| List.map myStringFilter (List.map doSomething inputs)) 
    --text <| myStringFilter <| doSomething (IFloat 14.83)
    -- text  <| toString <| myFloatFilter <| doSomething (IFloat -14.83)
    --text  <| toString <| myIntFilter <| doSomething (INumber 5)
like image 43
KK. Avatar answered Sep 24 '22 12:09

KK.


There's no such function in the core libraries. You'd need to write your own, which is half-done for you because you can reverse engineer elm-repl.

like image 24
Charles Maria Avatar answered Sep 21 '22 12:09

Charles Maria