2016-04-10 70 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代碼中可能熟悉的那樣)需要隨所有值一起執行。

我相信這是不可能的運行時類型內省會添加到像榆樹語言。在運行時需要檢查類型是代碼設計不佳的代碼。