Types 将char list转换为int list时键入ML list

Types 将char list转换为int list时键入ML list,types,functional-programming,sml,smlnj,ml,Types,Functional Programming,Sml,Smlnj,Ml,我在将字符列表转换为整数列表时遇到了一个问题。我的目标是基本上取一个像325这样的数字,让它返回一个[3,2,5]的列表。到目前为止,我所做的是获取数字,然后将其转换为字符串,然后将其分解为字符数组。然后,我想将每个字符转换为相应的int。当我将我的字符列表映射为fn c=>char.ordc时,字符列表将变成一个?.int列表,这将阻止我对其执行+和-操作。我是ML的新手,对它的类型系统没有很强的把握,但对我来说似乎很奇怪 代码如下: open IntInf; fun fact_helper

我在将字符列表转换为整数列表时遇到了一个问题。我的目标是基本上取一个像325这样的数字,让它返回一个[3,2,5]的列表。到目前为止,我所做的是获取数字,然后将其转换为字符串,然后将其分解为字符数组。然后,我想将每个字符转换为相应的int。当我将我的字符列表映射为fn c=>char.ordc时,字符列表将变成一个?.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列表类型。原始问题可以如下所示。

如果要将数字转换为其数字列表,可以使用此递归公式@is list appending运算符

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];

如果您想将一个数字转换为它的数字列表,可以使用这个递归公式@is list appending操作符

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];

问题是您确实打开了IntInf,因此类型int和operators+以及friends现在引用IntInf模块。普通的int类型被IntInf.int遮蔽,因此被打印为?.int SML/NJ使用伪语法?.x引用不可访问范围中的名称。ord返回普通的int类型

因此,您的代码不一定有什么问题,但开放可能会产生混乱的效果。通常应避免在顶级作用域中使用open


如果您真的希望num-to-digits函数使用无限整数进行计算,那么您必须包装对IntInf.fromInt或仅仅是fromInt的调用,因为IntInf是围绕Char.ord c打开的。

问题是您确实打开了IntInf,因此int和operators+以及friends现在引用IntInf模块。普通的int类型被IntInf.int遮蔽,因此被打印为?.int SML/NJ使用伪语法?.x引用不可访问范围中的名称。ord返回普通的int类型

因此,您的代码不一定有什么问题,但开放可能会产生混乱的效果。通常应避免在顶级作用域中使用open


如果您确实希望num to digits函数使用无限整数进行计算,那么您必须包装对IntInf.fromInt的调用,或者只对fromInt进行调用,因为IntInf是围绕Char.ord c打开的。

首先对您的代码进行一些反馈:

fn c=>Char.ord c中的内括号不是必需的。 因为Char.ord相当于fn c=>Char.ord c,所以可以编写映射ord chars。 有趣的阶乘n:int=。。。这并不意味着你认为这意味着什么。这里的:int部分是指阶乘的返回类型,顺便说一句,它与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和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
或者,如果您意识到语法sugar op::与fn d完全相同,res=>d::res,并且还对参数n执行了以下操作:

或递归应用的数字总和,直到剩下一个数字:

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

首先是对代码的一些反馈:

fn c=>Char.ord c中的内括号不是必需的。 因为Char.ord相当于fn c=>Char.ord c,所以可以编写映射ord chars。 有趣的阶乘n:int=。。。这并不意味着你认为这意味着什么。这里的:int部分是指阶乘的返回类型,顺便说一句,它与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和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
或者,如果您意识到语法sugar op::与fn d完全相同,res=>d::res,并且还对参数n执行了以下操作:

或递归应用的数字总和,直到剩下一个数字:

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

我在回答中添加了一些通用代码反馈。我在回答中添加了一些通用代码反馈。