查看完整版本 : Practice Functional Programming With C#

form5 2017-12-9 12:36 AM

Practice Functional Programming With C#

test with layumba  library

using LaYumba.Functional;
using System;
namespace FunctionalCSharpTest
{
    using static F;
    public class MyController
    {
        static Func<int, Option<int>> f = i => i % 2 == 0 ? Some(i) : None;

        public Option<int> Calculate(string s)
        {
            return Int
                    .Parse(s)
                    .Bind(f);
        }
    }

    class  Program
    {
        static void Main()
        {
            var controller = new MyController();

            Console.WriteLine(controller.Calculate("10")); //Some(10)
            Console.WriteLine(controller.Calculate("")); //None
            Console.WriteLine(" Press Any Key to Quit");
            Console.ReadKey();
        }
    }
}

fitcat07 2017-12-9 08:09 AM

唔太熟C#,可唔可以用auto,唔駛直接寫Func< int, Option<int> >?咁做好verbose

另外,同 f(Int.Parse(s))有冇分別?如無,邊個做法好尐?

Susan﹏汪汪 2017-12-9 08:26 AM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-9 08:09 AM 發表 [url=http://www.discuss.com.hk/redirect.php?goto=findpost&pid=472122000&ptid=27110670][img]http://www.discuss.com.hk/images/common/back.gif[/img][/url]
唔太熟C#,可唔可以用auto,唔駛直接寫Func< int, Option >?咁做好verbose

另外,同 f(Int.Parse(s))有冇分別?如無,邊個做法好尐? [/quote]
C#可以用var

問題係如果唔寫明個type
個i就唔知係咩type、過唔到compiler

Susan﹏汪汪 2017-12-9 08:37 AM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-9 08:09 AM 發表 [url=http://www.discuss.com.hk/redirect.php?goto=findpost&pid=472122000&ptid=27110670][img]http://www.discuss.com.hk/images/common/back.gif[/img][/url]
唔太熟C#,可唔可以用auto,唔駛直接寫Func< int, Option >?咁做好verbose

另外,同 f(Int.Parse(s))有冇分別?如無,邊個做法好尐? [/quote]
汪汪未睇過LaYumba係做D乜
佢應該係寫緊

一個f : (Int) -> Int?

因為個f只可以接受non-nil Int
而Int.Parse(s)是返回null

所以f(Int.Parse(s))係唔可能
而佢用的Bind就是maybe monad

用swift的寫法就是
optional.flatMap(f)

form5 2017-12-9 12:41 PM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-9 08:09 AM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472122000&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]
唔太熟C#,可唔可以用auto,唔駛直接寫Func< int, Option >?咁做好verbose

另外,同 f(Int.Parse(s))有冇分別?如無,邊個做法好尐? [/quote]

1. Func 不可以用var declear,  長少少好會難睇

2. LaYumba Fuctinonal 的 Int.Parse (s) 出 Option<int>
    而 f 係食 int 出 Optional<int> ,  signature 吾同,做不到

因為係 asp.net controller 的API 入面, string s  argument 好多時要check null先 , 而加就 可以在不改变現有 API  signature 的情况下
用 option 包住佢,然後用bind 一個 function 去 继续 做 嘢

form5 2017-12-9 12:45 PM

[quote]原帖由 [i]Susan﹏汪汪[/i] 於 2017-12-9 08:37 AM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472122670&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]

汪汪未睇過LaYumba係做D乜
佢應該係寫緊

一個f : (Int) -> Int?

因為個f只可以接受non-nil Int
而Int.Parse(s)是返回null

所以f(Int.Parse(s))係唔可能
而佢用的Bind就是maybe monad

用swift的寫法就是
option ... [/quote]
Bind 同 flatMap 都差不多,除左 Optional 件衫 ,有 料到先做嘢

Susan﹏汪汪 2017-12-9 01:06 PM

[quote]原帖由 [i]form5[/i] 於 2017-12-9 12:45 PM 發表 [url=http://www.discuss.com.hk/redirect.php?goto=findpost&pid=472130930&ptid=27110670][img]http://www.discuss.com.hk/images/common/back.gif[/img][/url]

Bind 同 flatMap 都差不多,除左 Optional 件衫 ,有 料到先做嘢 [/quote]
汪汪寫慣左swift
呢種寫法同呼吸一樣

睇汪汪的GitHub 寫的code
周圍都一堆map flatMap filter

darigold 2017-12-9 01:29 PM

Functional program 有一個問題,d code 好難讀!當然,難或者易係一件好個人既事。

我們做一個小實驗試試。

以下係一個問題。[code]Tourism 1 (file name: tourism1.pl)
Connor intends to plan a tour of Melbourne, accompanied by a group of colleagues. In order to visit the most desirable locations, he has asked the group members to rank the possible locations in order of preference. However, upon collating the data, he finds each colleague has stated preferences for only some of the locations.
Given a set L of locations, and partial rankings R = [R1, ..., Rn], we want to find the ordering of L which is most consistent with R. That is, the ordering of L which minimizes the sum of the number times each partial ranking is violated. Note that if several people have a violated preference, it is counted for each person. Similarly, preferences are transitive: so given a ranking [1, 2, 3], the ordering [3, 2, 1] has 3 violations.
Input formatAn input file contains the following facts:
One fact people(N), specifying the number of people.One fact locations(M), specifying the number of locations.One fact preferences(K), giving the number of stated preferences.A relation consisting of facts of the form order(P, X, Y), that person P ranked location X above location Y.Output format
The output query should return exactly one result of the form violations(V), where V is the number of preference violations of the optimal ranking.[/code]呢度係一段 prolog code[code]sequence(0).

sequence(X) :- sequence(Y), X is Y + 1.

pick([H|T], H, T).

pick([H|T], M, [H|Z]) :- pick(T, M, Z).

choices(1, [1]).

choices(X, [X|T]) :- X \= 1, Y is X - 1, choices(Y, T).

prefer(PERSON, SRC, DST) :- order(PERSON, SRC, DST).

prefer(PERSON, SRC, DST) :- order(PERSON, SRC, IMM), prefer(PERSON, IMM, DST).

all_preferences(RESULT) :- findall([SRC,DST], prefer(_, SRC, DST), RESULT).

state_transition([], VIOLATION, _, [], VIOLATION).

state_transition([[CHOICE,_]|INPUT_TAIL], INPUT_VIOLATION, CHOICE, OUTPUT_PREFERENCES_TAIL, OUTPUT_VIOLATION) :-   state_transition(INPUT_TAIL, INPUT_VIOLATION, CHOICE, OUTPUT_PREFERENCES_TAIL, OUTPUT_VIOLATION).

state_transition([[_,CHOICE]|INPUT_TAIL], INPUT_VIOLATION, CHOICE, OUTPUT_PREFERENCES_TAIL, OUTPUT_VIOLATION) :-  state_transition(INPUT_TAIL, INPUT_VIOLATION, CHOICE, OUTPUT_PREFERENCES_TAIL, OUTPUT_VIOLATION_TAIL),   OUTPUT_VIOLATION is OUTPUT_VIOLATION_TAIL + 1.

state_transition([[SRC,DST]|INPUT_TAIL], INPUT_VIOLATION, CHOICE, [[SRC,DST]|OUTPUT_PREFERENCES_TAIL], OUTPUT_VIOLATION) :-   SRC \= CHOICE,   DST \= CHOICE,   state_transition(INPUT_TAIL, INPUT_VIOLATION, CHOICE, OUTPUT_PREFERENCES_TAIL, OUTPUT_VIOLATION).

search([],_,_,V,[],V).

search(CHOICES, CONSTRAINT, INPUT_PREFERENCES, INPUT_VIOLATION, [CHOICE|TAIL_ANSWER], OUTPUT_VIOLATION) :-   pick(CHOICES, CHOICE, REMAINDER),   state_transition(INPUT_PREFERENCES, INPUT_VIOLATION, CHOICE, OUTPUT_PREFERENCES, IMM_VIOLATION),   IMM_VIOLATION =< CONSTRAINT,  search(REMAINDER, CONSTRAINT, OUTPUT_PREFERENCES, IMM_VIOLATION, TAIL_ANSWER, OUTPUT_VIOLATION).

violations(CONSTRAINT) :- all_preferences(ALL_PREFERENCES), locations(LOCATIONS), choices(LOCATIONS, CHOICES), sequence(CONSTRAINT), search(CHOICES, CONSTRAINT, ALL_PREFERENCES, 0, _, _), !.[/code]我冇 obfuscate 過段 code ,只係 delete 晒所有 comment ,睇係有冇人睇得明段 code 點 solve 個 problem ?

[[i] 本帖最後由 darigold 於 2017-12-9 01:50 PM 編輯 [/i]]

Susan﹏汪汪 2017-12-9 02:03 PM

[quote]原帖由 [i]darigold[/i] 於 2017-12-9 01:29 PM 發表 [url=http://www.discuss.com.hk/redirect.php?goto=findpost&pid=472132477&ptid=27110670][img]http://www.discuss.com.hk/images/common/back.gif[/img][/url]
Functional program 有一個問題,d code 好難讀!當然,難或者易係一件好個人既事。

我們做一個小實驗試試。

以下係一個問題。Tourism 1 (file name: tourism1.pl)
Connor intends to plan a tour of Melbou ... [/quote]
與其話functional programming 難明

汪汪連prolog的語法同keywords 都唔了解

fitcat07 2017-12-9 02:24 PM

[quote]原帖由 [i]Susan﹏汪汪[/i] 於 2017-12-9 08:26 AM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472122353&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]

C#可以用var

問題係如果唔寫明個type
個i就唔知係咩type、過唔到compiler [/quote]
個lambda function有用% operator,應只可用於int type,理論上compiler can infer the type as int.

fitcat07 2017-12-9 02:33 PM

[quote]原帖由 [i]Susan﹏汪汪[/i] 於 2017-12-9 08:37 AM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472122670&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]

汪汪未睇過LaYumba係做D乜
佢應該係寫緊

一個f : (Int) -> Int?

因為個f只可以接受non-nil Int
而Int.Parse(s)是返回null

所以f(Int.Parse(s))係唔可能
而佢用的Bind就是maybe monad

用swift的寫法就是
option ... [/quote]
問題係f嘅type係Func< int, Option< int > >,就咁睇係食int,傳回Option< int >,亦即 int -> Option int,令人混淆。
點解f嘅type唔係 Func< Option<int>, Option< int > >?
我諗所有魔法(Monad)係Bind做咗。用Bind就可以對一個食正常非Option type嘅function,變成可以食Option< >。

Susan﹏汪汪 2017-12-9 02:34 PM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-9 02:24 PM 發表 [url=http://www.discuss.com.hk/redirect.php?goto=findpost&pid=472134561&ptid=27110670][img]http://www.discuss.com.hk/images/common/back.gif[/img][/url]

個lambda function有用% operator,應只可用於int type,理論上compiler can infer the type as int. [/quote]
唔係

Strong typed語言只可以由已知typed variables 去推算可用的methods 同operation

fitcat07 2017-12-9 02:34 PM

明白了,謝。

Susan﹏汪汪 2017-12-9 02:38 PM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-9 02:33 PM 發表 [url=http://www.discuss.com.hk/redirect.php?goto=findpost&pid=472134919&ptid=27110670][img]http://www.discuss.com.hk/images/common/back.gif[/img][/url]

問題係f嘅type係Func< int, Option< int > >,就咁睇係食int,傳回Option< int >,亦即 int -> Option int,令人混淆。
點解f嘅type唔係 Func< Option, Option< int > >?
我諗所有魔法(Monad)係Bind做咗。 ... [/quote]
[quote]點解f嘅type唔係 Func< Option<int>, Option< int > >?[/quote]

由一個domain map去另一個domain的function 好常見

No nullable -> nullable 也都只是一個domain map去另一個domain 的例子

fitcat07 2017-12-9 02:38 PM

[quote]原帖由 [i]Susan﹏汪汪[/i] 於 2017-12-9 02:34 PM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472134936&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]

唔係

Strong typed語言只可以由已知typed variables 去推算可用的methods 同operation [/quote]
i % 2 == 0 ? Some(i) : None
%只係int先可以用 => i is type int
Some(i) => Option< int > since i is type int
None => Option< int > since Some(i) can be returned
好明顯f嘅type係:int -> Option< int >

fitcat07 2017-12-9 02:40 PM

[quote]原帖由 [i]darigold[/i] 於 2017-12-9 01:29 PM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472132477&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]
Functional program 有一個問題,d code 好難讀!當然,難或者易係一件好個人既事。

我們做一個小實驗試試。

以下係一個問題。Tourism 1 (file name: tourism1.pl)
Connor intends to plan a tour of Melbou ... [/quote]
Prolog 應係 logic programming,並非 functional programming,對嗎?

Susan﹏汪汪 2017-12-9 02:43 PM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-9 02:38 PM 發表 [url=http://www.discuss.com.hk/redirect.php?goto=findpost&pid=472135091&ptid=27110670][img]http://www.discuss.com.hk/images/common/back.gif[/img][/url]

i % 2 == 0 ? Some(i) : None
%只係int先可以用 => i is type int
Some(i) => Option< int > since i is type int
None => Option< int > since Some(i) can be returned
好明顯f嘅type係:int -> Option< int ... [/quote]
[quote]%只係int先可以用[/quote]

集中睇你呢一行做的定義
你係由operator 去推算variables 的type
還是由已知typed的variables 去推算可用的operator?

如果寫慣weak type language 未必會諗到呢個問題

fitcat07 2017-12-9 02:44 PM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-9 02:38 PM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472135091&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]

i % 2 == 0 ? Some(i) : None
%只係int先可以用 => i is type int
Some(i) => Option< int > since i is type int
None => Option< int > since Some(i) can be returned
好明顯f嘅type係:int -> Option< int ... [/quote]
雖然知道係 int -> Option< int >,但係無法得知結果係 Func< int, Option< int > >,除非C# build in Func 呢個type,作為function。
始終C#唔係FP語言,係麻煩好多。

Susan﹏汪汪 2017-12-9 02:54 PM

[quote]原帖由 [i]Susan﹏汪汪[/i] 於 2017-12-9 02:43 PM 發表 [url=http://www.discuss.com.hk/redirect.php?goto=findpost&pid=472135275&ptid=27110670][img]http://www.discuss.com.hk/images/common/back.gif[/img][/url]



集中睇你呢一行做的定義
你係由operator 去推算variables 的type
還是由已知typed的variables 去推算可用的operator?

如果寫慣weak type language 未必會諗到呢個問題 [/quote]
話說
講起呢個

Swift個型別推算system係汪汪見過最複雜的
也都是最多bugs的

寫開swift一定會見識過「Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions」
因為swift的compiler 用比起C++/C#/Java更general 的方法做型別推算
所以好似呢D function
[code]
func zero<T: Integer>() -> T {
    return 0
}
[/code]
Swift都可以行到

之前swift 4未正式果時
汪汪有份推翻左type system針對closure expressions的一個改動

[[i] 本帖最後由 Susan﹏汪汪 於 2017-12-9 03:06 PM 編輯 [/i]]

Susan﹏汪汪 2017-12-9 02:59 PM

Swift如果寫lambda的話可以係

[code]
var f1: (Int) -> Int? = { (x: Int) -> Int? in x % 2 == 0 ? x : nil }

var f2: (Int) -> Int? = { x in x % 2 == 0 ? x : nil }

var f3: (Int) -> Int? = { $0 % 2 == 0 ? $0 : nil }

var f4 = { (x: Int) -> Int? in x % 2 == 0 ? x : nil }

[/code]

[[i] 本帖最後由 Susan﹏汪汪 於 2017-12-9 03:12 PM 編輯 [/i]]

fitcat07 2017-12-9 03:12 PM

[quote]原帖由 [i]Susan﹏汪汪[/i] 於 2017-12-9 02:43 PM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472135275&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]



集中睇你呢一行做的定義
你係由operator 去推算variables 的type
還是由已知typed的variables 去推算可用的operator?

如果寫慣weak type language 未必會諗到呢個問題 [/quote]
同意。但係weak type language就幾可肯定做唔到type inference。

Haskell係static and strongly typed language。以下咁寫:

f i = if i == 2 then
         Just(0)
      else
         Nothing
compiler就會infer as:
f :: (Num a1, Num a, Eq a) => a -> Maybe a1

因為2係Num type,(==)operator can only applies to the same type,所以i亦係Num type。
Just(0) => 0係Num type,Just(0)就係Maybe Num type。
Nothing同Just(0)同type。
因為Num type可以分為Real and Fractional,而Real又可分為Integral and RealFrac,Fractional又可分為RealFrac and Floating,所以最後係有兩個Num types,一個係輸入參數,另一個係傳回值。兩者都係Num,但可以有唔同sub-types。

fitcat07 2017-12-9 04:25 PM

C#做FP好唔方便,用Haskell就好簡單:[code]import Text.Read

f :: Int -> Maybe Int
f i | i `mod` 2 == 0 = Just(i)
    | otherwise      = Nothing

parseInt :: String -> Maybe Int
parseInt = readMaybe

main :: IO ()
main = do
    print $ parseInt "10" >>= f
    print $ parseInt ""   >>= f[/code]那個 >>= operator 就等同 Bind。

form5 2017-12-9 09:11 PM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-9 04:25 PM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472139346&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]
C#做FP好唔方便,用Haskell就好簡單:import Text.Read

f :: Int -> Maybe Int
f i | i `mod` 2 == 0 = Just(i)
    | otherwise      = Nothing

parseInt :: String -> Maybe Int
parseInt = readMaybe

... [/quote]
in C# way[code]using LaYumba.Functional;
using System;
class Program
{
  public static Func < string, Option <  int > >  f2=s
     => Int
            .Parse(s)
            .Where(i => i % 2 == 0);
  static void Main()
  {
      Console.WriteLine(f2("10")); //Some(10)
      Console.WriteLine(f2("")); //None
  }
}[/code]

[[i] 本帖最後由 form5 於 2017-12-9 09:15 PM 編輯 [/i]]

darigold 2017-12-10 01:54 AM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-9 02:40 PM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472135150&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]
Prolog 應係 logic programming,並非 functional programming,對嗎?
[/quote]
係喎,唔記得左 tim …
代碼一樣難讀,唉…

fitcat07 2017-12-10 08:48 AM

[quote]原帖由 [i]darigold[/i] 於 2017-12-10 01:54 AM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472162696&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]

係喎,唔記得左 tim …
代碼一樣難讀,唉… [/quote]
想當年要學prolog,只係寫解迷宮之類簡單問題,果陣時重搞唔清楚recursion同back tracking嘅分別,呵呵。

我諗要寫易讀程式碼,根本係甚艱難,但亦非常重要。而普遍上,大多係屬於難讀,變相難於維護。
坊間有好多書本,正是針對此現象而推出。較為出名有:

[list][*]Code Completed, 2nd Edition[*]Clean Code[*]Refactoring[/list]


雖然我有讀以上3本書,再加上不少相關書籍,但係仍然覺得我寫嘅程式碼,離易讀還有一大段距離。

我覺得程式碼是否易讀,是哪個programming paradigm無太大關係,當然讀者係要熟識programming language and programming paradigm,因當中有不少idioms。關鍵係作者。以下係[url=https://en.wikiquote.org/wiki/Martin_Fowler]Martin Fowler[/url]名句:

[i]Any fool can write code that a computer can understand. Good programmers write code that humans can understand.[/i]

fitcat07 2017-12-10 10:41 PM

[quote]原帖由 [i]form5[/i] 於 2017-12-9 09:11 PM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472151384&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]

in C# wayusing LaYumba.Functional;
using System;
class Program
{
  public static Func < string, Option <  int > >  f2=s
     => Int
            .Parse(s)
            .Where(i => i % 2 == 0);
... [/quote]
我認為我嘅版本似乎對應一樓嘅C#碼多尐。
以下版本似你新版本:[code]import Text.Read
import Control.Monad

f2 :: String -> Maybe Int
f2 s = even <$> i >>= guard >> i
       where i = parseInt s

parseInt :: String -> Maybe Int
parseInt = readMaybe

main :: IO ()
main = do
    print $ f2 "10"
    print $ f2 ""
    print $ f2 "9"[/code]

form5 2017-12-11 12:03 AM

[quote]原帖由 [i]fitcat07[/i] 於 2017-12-10 10:41 PM 發表 [url=http://computer.discuss.com.hk/redirect.php?goto=findpost&pid=472203068&ptid=27110670][img]http://computer.discuss.com.hk/images/common/back.gif[/img][/url]

我認為我嘅版本似乎對應一樓嘅C#碼多尐。
以下版本似你新版本:import Text.Read
import Control.Monad

f2 :: String -> Maybe Int
f2 s = even  i >>= guard >> i
       where i = parseInt s

parseIn ... [/quote]
I see

stupidsing 2017-12-12 03:12 PM

darigold 唔好蝦人,我明明見過你寫 prolog interpreter.
同埋,prolog 唔係 functional, 係 horn clause, predicate-based logic...

Susan﹏汪汪 2017-12-12 03:16 PM

汪汪有D好奇

prolog個引擎係咪窮舉法
頁: [1]
查看完整版本: Practice Functional Programming With C#