2017-12-18 132 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>

相關問題