2012-07-15 19 views
1

所以首先我很抱歉问this question。但是“逃离Zurg”的文章帮助了我很多,我可以为狼山羊白菜问题写出自己的解决方案。我正在下面放置我的代码。我希望你能告诉我F#狼山羊卷心菜

  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 
    
+1

对我来说看起来很实用。可能与我在Scheme中写的风格相同。 – leppie 2012-07-15 08:47:06

+0

首选在F#中将printfn添加到Console.WriteLine。 – Asik 2012-07-15 20:31:13

+0

@Dr_Asik:当没有格式说明符时,首选'stdout.WriteLine'到F#中的'printfn'。 ; - ] – ildjarn 2012-07-16 07:34:41

回答

6

的代码看起来很实用。我做了一些改变。首先,我会用来表示移动,并且还有一些小的建议...

表示形式。您使用列表表示致命组合,因此["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