2016-04-10 21 views
2

是否存在检查Elm中变量类型的函数?例如(REPL):Elm - 检查值的类型

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

这样做的动机是,当您使用Signal.map[n]的情况通常出现,并非所有的参数将被应用的功能的信号 - 然后他们通常是“使用Signal.constant提升为信号 - 如果我可以检查这些参数的类型,我可以创建一个函数Signal.allSigMap[n],它会自动将这些参数转换为信号。

所以

Signal.map2 grandFatherClock clockSignalElement (Signal.constant cabinetElement) 

成为

Signal.allSigMap2 grandFatherClock clockSignalElement cabinetElement 

可能是不好的做法虽然。请告诉我。

+0

你能解释一下为什么要检查一个变量的类型吗?也许显示你将如何使用这样的功能? – ianmjones

+0

当然 - 更新的问题。 – category

回答

10

我会先回应您打算使用returnType作为根据需要向Signal推广类型的方法。这将需要returnType或其他一些函数实际返回一个类型而不是String,因为没有其他方法可以使类型检查程序开心。

这样一个函数不存在,不能像现在这样存在于Elm中。你要求的东西可以检查一个值编译时间的类型,然后运行该类型的函数。

要明白为什么这与现在存在于榆树中的东西完全不同,让我们假设存在这样的函数。

returnType : a -> ? 

我们立即面临returnType的确切类型的第一个问题。让我们手工处理这个,并说我们有一个类型为Type(它有自己的一套逻辑问题,我们将放在一边)。

returnType : a -> Type 

我们该如何实际使用此功能?据推测,它将能够进入类型签名,因为它正在返回一个类型。

x : returnType 5 

现在是一种签名从榆树一切完全不同。有一个数字文字(和一个功能)!突然之间,你可以开始写这样的事情。

y = 5 

x : returnType y 
x = 6 

这超出了Elm的类型系统所能做到的。这种(令人兴奋的和强大的)类型水平和价值水平混合被称为dependent typing并且不存在主流完全依赖类型语言;与主流最接近的东西可能是Coq,Agda,Idris和ATS,这些都很模糊。

至于从字面上讲,有一个函数returnType : a -> String可以打印出一个代表值的类型的字符串,但这在Elm中也是不可能的,尽管由于其他原因。这样的函数(它是运行时应用的东西)必须能够重建关于运行时值的类型信息,但Elm的运行时值只是Javascript值;他们已经被剥夺了他们的榆树类型。您必须从Javascript值重建原始的Elm类型(并非总是可能,因为不同的类型可能会以相同的Javascript值结束),或者需要特殊的编译器支持。

在Elm REPL的情况下,选择后者。整个REPL是用Haskell编写的,它利用了Haskell运行时如何实现Elm类型。

+3

低估答案 –

1

核心库中没有这样的功能。你需要写自己的,这是你的一半,因为你可以逆向工程榆树repl。

+0

如果我没有弄错,elm-repl在Haskel中实现,实际上不是Elm。 – konung

1

我也想知道,为什么没有}这种TYPEOF在榆树。然后仔细阅读文档以深入了解FRP,它变得清晰起来!您应该始终知道数据的形状。为了在Elms Tagged Unions中使用case ...的模式,您应该可以通过过滤已知类型来访问所需的值。警告,所有分支的情况下必须是相同的类型,但是这并不排除你使用一个具有所有已知类型的超集和虚拟警戒值的元组,以允许你访问你想要的类型。

下面见代码来加以说明:

假设:

使用

1.您所希望的类型的标签

2,采用定点值

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) 
2

Thi由于类型擦除(https://en.wikipedia.org/wiki/Type_erasure),s是不可能的(也不是可取的,我会争辩)。因为elm中的所有内容都必须输入正确,所以编译器可以在编译时验证所有类型。一旦完成,它可以安全地从编译的代码中移除实际运行的所有类型信息。这实际上使得代码更高效,因为在运行时不需要类型信息(或运行时类型检查,就像您在典型的JavaScript代码中可能熟悉的那样)需要随所有值一起执行。

我相信这是不可能的运行时类型内省会添加到像榆树语言。在运行时需要检查类型是代码设计不佳的代码。