2017-12-18 135 views
1

鉴于以下组代表一个存储类型:F#对于列表中的每个元素,应用功能,在列表元素中,b

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')其中pkast'价格是通过除去kast获得的新的库存。

例子:

let 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))])

+0

你'get''代码失败'无与伦比 '['' – TheQuickBrownFox

+0

固定编译 - 笨手笨脚。 – Khaine775

+0

我不明白您的预期产出中的数字是如何计算的。减法应该发生在'a2'上吗?为什么'300'? –

回答

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的实现,让我们重命名现有功能getgetArticle

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预计需要交换这两个参数的文件夹函数。

所以,让我们constuct文件夹功能,其中,(加)检索到的文章至今累积的总价格:

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>

相关问题