F#对于列表a中的每个元素,将函数应用于列表b中的元素

时间:2017-12-18 12:47:36

标签: f#

给出代表商店的以下类型集:

type Article    = string
type Amount     = int
type Price      = int
type Desc       = Amount*Price
type Stock      = (Article*Desc) list
type Order      = Article * Amount
type Status<'a> = Result of 'a | Error of string

我想创建一个带OrderStock并返回Status<Price * Stock>的函数。 get (a,k) st下面定义的函数的值为Result (p,st'),其中pka的价格,而st'是新库存的价格通过移除st kalet rec get (a,k) st = match st with | (a',(n',p'))::rest when a'=a -> Result (p'*k,(a',(n'-k,p'))::rest) | (a',(n',p'))::rest -> match get (a,k) rest with | Result (price,stock) -> Result (price,(a',(n',p'))::stock) | Error e -> Error e get ("a2", 10) st val it : int * (string * (int * int)) list = Result (200, [("a1", (100, 10)); ("a2", (40, 20)); ("a3", (25, 40))]) 获得。

示例:

Order list

现在,如果我采用get [("a2",10);("a1",10)] st,我将如何做到这一点?

例如Result (300, [("a1", (90, 10)); ("a2", (40, 20)); ("a3", (25, 40))])会返回void loop() { int r = random(10,100); int s = random(10,100); int t = random(10,100); Serial.print("R"+String(r)); Serial.print("S"+String(s)); Serial.print("T"+String(t)); delay(1000); }

1 个答案:

答案 0 :(得分:0)

type Article    = string
type Amount     = int
type Price      = int
type Desc       = Amount * Price
type Stock      = (Article * Desc) list
type Order      = Article * Amount
type Status<'a> = Result of 'a | Error of string

首先,由于您要求实现函数get,我们将现有函数get重命名为getArticle

let rec getArticle (a, k) st =
    match st with
        | (a', (n', p')) :: rest when a' = a -> Result (p' * k, (a', (n' - k, p')) :: rest)
        | (a', (n', p')) :: rest -> 
            match getArticle (a, k) rest with
                | Result (price, stock) -> Result (price, (a', (n', p')) :: stock)
                | Error e               -> Error e
        | [] -> Error "Article not in stock"

我还添加了一个额外的案例来摆脱“不完整模式匹配”警告。

您的问题的答案是List.fold

List.fold的第一个参数是'State -> 'ElementType -> 'State类型的文件夹函数。在这个问题中,'ElementTypeOrder

getArticle几乎完成了文件夹功能应该做的事情:在遍历一个元素时计算下一个状态 - 在这个问题中:列表中的一个顺序。但不完全是:

  • getArticle将输入状态视为Stock,但作为输出状态返回Status<Price * Stock>,其中额外Price是检索到的文章的总价格(目前为止) )。 List.fold期望文件夹功能的输入和输出状态是相同的类型。
  • getArticle将列表中的元素作为第一个参数 - 在此问题中具有类型Order - ,并将第二个参数作为输入状态。 List.fold需要一个文件夹函数来交换这两个参数。

所以,让我们构建一个文件夹功能,其中累计(添加)到目前为止检索到的文章的总价格:

let folder status order =
   match status with
       | Result (totalPriceSoFar, stock) ->
           match getArticle order stock with
               | Result (price, st) -> Result (totalPriceSoFar + price, st)
               | Error e -> Error e
       | Error f -> Error f

我们现在已经完成了。

List.fold的第二个论点是初始状态 - 在这个问题中:Result初始股票和到目前为止的总价格初始化为0

List.fold的第三个参数是迭代的列表 - 在这个问题中:订单列表。

let get orders initialStock =
    let initialStatus = Result (0, initialStock)
    List.fold folder initialStatus orders

let initialStock = [("a1", (100, 10)); ("a2", (50, 20)); ("a3", (25, 40))]
get [("a2", 10); ("a1", 10)] initialStock

结束语

您选择将Stock类型定义为(Article * Desc) list。鉴于您使用此列表基本上作为查找地图,其中文章不能有2个价格或2个金额,为什么不选择Map<Article, Desc>