Hacker News new | ask | show | jobs
by shawndumas 5424 days ago
Some F# to ponder:

    type LogicGate =
        | ON
        | OFF
        | NAND of LogicGate * LogicGate
        | NOT  of LogicGate
        | AND  of LogicGate * LogicGate
        | OR   of LogicGate * LogicGate
        | NOR  of LogicGate * LogicGate
        | XOR  of LogicGate * LogicGate
        | XNOR of LogicGate * LogicGate

    let rec evaluate input =
        match input with
        | ON         -> true
        | OFF        -> false
        | NAND(a, b) -> not ((evaluate a) && (evaluate b))
        | NOT(a)     -> (evaluate (NAND(a, a)))
        | AND(a, b)  -> (evaluate (NOT(NAND(a, b))))
        | OR(a, b)   -> (evaluate (NAND(NOT(a), NOT(b))))
        | NOR(a, b)  -> (evaluate (NOT(OR(a, b))))
        | XOR(a, b)  -> (evaluate (AND(NAND(a, b), OR(a, b))))
        | XNOR(a, b) -> (evaluate (NOT(XOR(a, b))))

    [
        NAND(OFF, OFF);
        NAND(OFF, ON);
        NAND(ON,  OFF);
        NAND(ON,  ON)
    ] |> List.map (fun x -> printfn (evaluate x))
5 comments

While that's a very good example of what F# can do, I think the real value proposition of F# is that it can use anything from .NET. Take something like this for example:

  open System
  open System.Collections.Generic
  open System.Reflection
  
  type Config = string 
  type ISuperPlugin =
      abstract member Name : string
      abstract member Initialize : Config -> unit
  
  let loadedPlugins = Dictionary<string,ISuperPlugin>()
  
  let isPlugin (tp: Type) =
      tp.GetInterfaces()
      |> Seq.exists (fun t -> t.GetType() = typeof<ISuperPlugin>)
  
  let isPluginLoaded plugin =
      match loadedPlugins.TryGetValue(plugin) with
      | true, v -> true
      | _ -> false
  
  
  let loadPlugin typ = () // implement this
  
  let LoadPluginsFromAssembly path =
      let asm = Assembly.LoadFrom path
      asm.GetTypes()
      |> Seq.filter isPlugin
      |> Seq.filter (fun t -> not (isPluginLoaded t.Name))
      |> Seq.map loadPlugin
      |> ignore
  
  let loadAllPlugins plugins =
      plugins
      |> Seq.map (fun p -> async { LoadPluginsFromAssembly p })
      |> Async.Parallel
      |> ignore
Loads a bunch of plugins from assemblies in parallel. Haven't tested it but it should work with minor modifications to make it thread-safe.
Equivalent C# code (if you want to appreciate the brevity of F# or just understand what the code is doing):

    public abstract class LogicGate
    {
        public abstract bool Evaluate();
    }

    public abstract class BinaryLogic : LogicGate
    {
        protected LogicGate a, b;
        
        public BinaryLogic(LogicGate a, LogicGate b)
        {
            this.a = a;
            this.b = b;
        }
    }

    public class ON : LogicGate
    {
        public override bool Evaluate() { return true; }
    }

    public class OFF : LogicGate
    {
        public override bool Evaluate() { return false; }
    }

    public class NAND : BinaryLogic
    {
        public NAND(LogicGate a, LogicGate b) : base(a, b) { }       

        public override bool Evaluate() 
        { 
            return !(a.Evaluate() && b.Evaluate()); 
        }
    }

    public class NOT : LogicGate
    {
        LogicGate a;

        public NOT(LogicGate a)
        {
            this.a = a;
        }

        public override bool Evaluate() 
        { 
            return new NAND(a, a).Evaluate(); 
        }
    }

    public class AND : BinaryLogic
    {
        public AND(LogicGate a, LogicGate b) : base(a, b) { }
      
        public override bool Evaluate() 
        { 
            return new NOT(new NAND(a, b)).Evaluate(); 
        }
    }

    public class OR : BinaryLogic
    {
        public OR(LogicGate a, LogicGate b) : base(a, b) { }
      
        public override bool Evaluate() 
        { 
            return new NAND(new NOT(a), new NOT(b)).Evaluate(); 
        }
    }

    public class NOR : BinaryLogic
    {
        public NOR(LogicGate a, LogicGate b) : base(a, b) { }
       
        public override bool Evaluate() 
        { 
            return new NOT(new OR(a, b)).Evaluate(); 
        }
    }

    public class XOR : BinaryLogic
    {
        public XOR(LogicGate a, LogicGate b) : base(a, b) { }
       
        public override bool Evaluate() 
        { 
            return new AND(new NAND(a, b), new OR(a, b)).Evaluate(); 
        }
    }

    public class XNOR : BinaryLogic
    {
        public XNOR(LogicGate a, LogicGate b) : base(a, b) { }     

        public override bool Evaluate() { return new NOT(new XOR(a, b)).Evaluate(); }
    }
   

    class Program
    {
        public static void Main(string[] args)
        {
            var on = new ON();
            var off = new OFF();
            
            var result = new List<LogicGate>() 
            { 
                new NAND(on, off), 
                new NAND(off, on), 
                new NAND(on, off), 
                new NAND(on, on) 
            }
            .Select(x => x.Evaluate());

            Console.WriteLine(result);
        }
        
     }
The extra parentheses around the evaluates are not necessary, except in the last line. I'm fond of this pairing heap in F#:

    type 't heap = Empty | Heap of 't * 't heap list

    let findmin (Heap(x,_)) = x
    let merge h1 h2 = 
      match (h1,h2) with
      | Empty,h | h,Empty -> h
      | Heap(x,h1s),Heap(y,h2s) -> if x < y then Heap(x,h2::h1s) else Heap(y,h1::h2s)
    let deletemin (Heap(_,hs)) = List.fold merge Empty hs
    let insert h x = merge h (Heap(x,[]))
a bit rusty, but think this one's right too ( am using Peirce's arrow instead of Sheffer stroke )

type LogicGate = | ON | OFF | NOR of LogicGate * LogicGate | NOT of LogicGate | AND of LogicGate * LogicGate | OR of LogicGate * LogicGate | NAND of LogicGate * LogicGate | XOR of LogicGate * LogicGate | XNOR of LogicGate * LogicGate

    let rec evaluate input =
        match input with
        | ON         -> true
        | OFF        -> false
        | NOR(a, b) -> not ((evaluate a) || (evaluate b))
        | NOT(a)     -> (evaluate (NOR(a, a)))
        | OR(a, b)  -> (evaluate (NOT(NOR(a, b))))
        | AND(a, b)   -> (evaluate (NOR(NOT(a), NOT(b))))
        | NAND(a, b)  -> (evaluate (NOT(AND(a, b))))
        | XNOR(a, b)  -> (evaluate (OR(AND(a, b), NOR(a, b))))
        | XOR(a, b) -> (evaluate (NOT(XNOR(a, b))))

    [
        NOR(OFF, OFF);
        NOR(OFF, ON);
        NOR(ON,  OFF);
        NOR(ON,  ON)
    ] |> List.map (fun x -> printfn (evaluate x))
Curious: is this also valid ocaml?
Almost, |> isn't an operator in OCaml (although I think Batteries has something like |- that does the same thing) and printfn isn't in OCaml. Printf.printf is, but wouldn't work in this case (you'd need a format string). Also, List.map returns a new list, in OCaml you would probably want to do List.iter.
the |> operator is very very simple. ocaml implementation would look something like:

  let (|>) a b = b a ;;