2016-10-05 82 views
1

我一直在將字符列表轉換爲int列表時遇到問題。我的目標是基本上取一個數字,如325,並返回一個[3,2,5]的列表。到目前爲止,我所做的是取出數字,然後將其轉換爲字符串,然後將其分解爲char數組。然後我想將每個字符轉換爲相應的int。當我將char列表映射到fn c => Char.ord(c)時,char列表變成了一個?.int列表,這阻止了我對它進行操作(+, - )。我是ML新手,對其類型系統沒有很強的把握,但對我來說似乎很奇怪。將char列表轉換爲int列表時將ML列表打字

下面的代碼:

open IntInf; 

fun fact_helper (0, r : int) = r 
    | fact_helper (n : int, r : int) = fact_helper (n-1, n*r); 

fun factorial n:int = fact_helper (n, 1); 

fun num_to_digits n = 
    let val digits_as_chars = explode (IntInf.toString n); 
    in map (fn c => (Char.ord c)) digits_as_chars 
    end; 

理想情況下,我想能夠做到fn c => (Char.ord c) - 48在我的映射功能,以獲得真正的數字值。我以前做過類似的事情,但它現在可以工作,但現在不行,我不確定爲什麼我會得到?.int列表類型。原始問題可以發現爲Project Euler problem 20

+1

我添加了一些通用代碼反饋給我的答案。 –

回答

4

的問題是,你沒有open IntInf,所以該類型int和運營商+和朋友現在參考IntInf模塊。普通int類型受IntInf.int影響,因此打印爲?.int(SML/NJ使用僞語法?.x來引用來自不可訪問範圍的名稱)。 Char.ord返回普通int類型。

因此,您的代碼沒有任何錯誤,但open可能會產生混淆。通常應避免在頂級範圍內使用open

如果你真的想你num_to_digits函數來計算與無限的整數,那麼你就必須調用換到IntInf.fromInt(或只是fromInt,因爲IntInf被打開)圍繞Char.ord c

0

如果你想打開一個數字,以它的數字的列表,你可以使用這個遞歸公式(該@是列表追加操作)

list(digits(num)) = list(digits(num/10)) @ list(n % 10) 

這是如何在SMLNJ解決方案:

fun num_to_array 0 = [] 
| num_to_array n = num_to_array(n div 10) @ [n mod 10]; 
2

首先在你的代碼的一些反饋:

  • (fn c => (Char.ord c))的括號內是沒有必要的。
  • 由於Char.ord等於fn c => Char.ord c,所以您可以編寫map ord chars
  • fun factorial n:int = ...並不意味着你的想法。這裏的:int部分是指factorial的返回類型,它與n的類型相同。什麼你可能想說的,但沒有必要的,因爲類型推斷的說,就是:

    fun factorial (n : int) : int = ... 
    
  • 一般類型的註釋是不必要的。該代碼是相當可讀的簡單:

    fun fact_helper (0, r) = r 
        | fact_helper (n, r) = fact_helper (n-1, n*r); 
    
    fun factorial n = fact_helper (n, 1); 
    

下,建立在雙方的Andreas'es和galfisher的建議,你可能想要同時使用IntInf和數字運算符。此外,還有一個漂亮整潔的功能IntInf稱爲divMod,讓你倆的分工,其餘:

open IntInf 

fun digits n = 
    let fun aux n res = 
      case divMod (n, 10) of 
       (0, d) => d::res 
       | (n', d) => aux n' (d::res) 
    in aux n [] end 

但是你什麼時候會真正需要的數字列表?最有可能的是你想要在這個列表上遞歸併且構建其他的東西,例如數字的總和,或其他。通過與::摺疊

(* f is the operator that we fold with 
* e is the initial accumulated value (temporary result) 
* n is the number on which we fold across 
*) 
fun folddigits f e n = 
    case divMod (n, 10) of 
     (0, d) => f (d, e) 
     | (n', d) => folddigits f (f (d, e)) n' 

有了這個,你可以輕鬆地進行數字到列表:那遞歸模式 - - 訪問列表中的每個元素連續還不如直接應用到數字和概括成倍運營商:

fun digits n = folddigits (fn (d, res) => d::res) [] n 

或者,如果你認識到的語法糖op::是完全一樣fn (d, res) => d::res)和也對參數進行neta conversion

val digits = folddigits op:: [] 

或數字的總和(遞歸地應用,直到一個數字是左起):

val sum_of_digits = folddigits 
    (fn (d, res) => let val res = d + res in 
         if res < 10 then res else 1 + (res mod 10) 
        end) 0