【问题标题】:F# Wolf Goat CabbageF#狼山羊白菜
【发布时间】:2013-11-25 00:36:46
【问题描述】:

首先我很抱歉问this question。但是“逃离 Zurg”文章对我帮助很大,我可以编写自己的解决方案来解决 Wolf Goat Cabbage Problem。我在下面放置我的代码。我想让你告诉我

  1. 如果我的代码是按照真正的 F# 和函数式编程精神编写的
  2. 这是解决问题的最佳且良好的解决方案

    open System
    
    (* 
      The type direction determines which direction the human is present.
      Left means that Human is present on the left side of the bank.
      Right means human is present on the right side of the bank.
    *)
    type Direction =
      | Left
      | Right
    
    (*
      Master list of animals
    *)
    let Animals = ["Wolf"; "Goat"; "Cabbage"]
    
    let DeadlyCombinations = [["Wolf"; "Goat"];["Goat"; "Cabbage"];]
    
    let isMoveDeadly list1 list2 =
      List.exists (fun n -> n = list1) list2
    
    let rec MoveRight animals =
      match animals with
        | [] -> []
        | head::tail -> 
          if (isMoveDeadly tail DeadlyCombinations) then
            MoveRight tail @ [head]
          else
            Console.WriteLine("Going to move " + head)
            tail
    
    let ListDiff list1 list2 = List.filter (fun n -> List.forall (fun x -> x <> n) list1) list2
    
    let MoveLeft animals = 
      let RightList = ListDiff animals Animals 
      let ShouldTakeAnimal = isMoveDeadly RightList DeadlyCombinations
      if (ShouldTakeAnimal) then
        let x = List.head RightList
        Console.WriteLine("Going to move " + x + " back")
        [x]
      else
        Console.WriteLine("Farmer goes back alone")
        []
    
    let rec Solve direction animals =
        match animals with 
        | [] -> Console.WriteLine("Solved")
        | _ ->
            match direction with
            | Left -> Solve Right (MoveRight animals) 
            | Right -> Solve Left (animals @ (MoveLeft animals))
    
    [<EntryPoint>]
    let main args =
        Solve Left Animals
        0
    

【问题讨论】:

  • 对我来说看起来很实用。可能和我用 Scheme 写的风格一样。
  • 在 F# 中使用 printfn 优于 Console.WriteLine。
  • @Dr_Asik :当没有格式说明符时,在 F# 中首选 stdout.WriteLine 而不是 printfn。 ;-]

标签: f# river-crossing-puzzle


【解决方案1】:

代码看起来很实用。我会做一些改变。首先,我会使用 sets 来表示动作,还有一些小建议...

表示。您使用列表表示致命组合,因此["Goat"; "Wolf"]["Wolf"; "Goat"] 不同,如果您的算法以其他顺序生成移动,它不会检测到它是致命的举动。您应该尝试找到不会发生这种情况的表示,因此我会更改表示以使用集合:

let DeadlyCombinations = [set ["Wolf"; "Goat"]; set ["Goat"; "Cabbage"];] 

isMoveDeadly 函数中,您可以使用以下方法将移动转换为集合(但也许最好将代码更改为在任何地方使用集合):

let move = set list1

不必要的概括。除此之外,函数isMoveDeadly 总是将DeadlyMoves 作为第二个参数,所以我不会将它作为参数传递(这是不必要的概括),我会写:

let isMoveDeadly list = 
  let move = set list
  DeadlyCombinations |> List.exists (fun n -> n = move) 

效率提示。MoveRight 函数中,您使用的是效率非常低的list @ [element] 模式。这意味着您需要复制整个 list 以将元素附加到末尾。使用element::list(减少复制)将元素添加到前面然后反转列表更有效。如果您将致命动作表示为一组,我想您甚至不需要反转列表,所以我会写:

let rec MoveRight animals = 
  match animals with 
    | [] -> [] 
    | head::tail ->  
      if (isMoveDeadly tail) then 
        head :: (MoveRight tail)
      else 
        Console.WriteLine("Going to move " + head) 
        tail 

表示(再次)。您实现了自己的ListDiff 函数来找出给定列表中没有的动物。这表明使用集合(而不是列表)确实是一种更好的表示形式。如果你切换到集合,你可以使用内置函数Set.difference

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    • 2014-06-22
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 2019-07-27
    • 1970-01-01
    相关资源
    最近更新 更多