mono

2010/02/01 § コメントする

ubuntu9.10上でmono-develを入れて、以下のコードがコンパイルできた。

using System;
public class Program
{
public static int Main(string[] args)
{
Console.WriteLine("Hello World");
return 0;
}
}
$csc hello.cs
$./hello.exe
Hello World

lispとrubyとpythonと その4 Cライブラリの呼び出し(python) の追記

2009/02/21 § コメントする

lispとrubyとpythonと その4 Cライブラリの呼び出し(python) – テンポラリにfgshunさんからコメントをもらったので試してみた。

呼び出しているcライブラリはこんどもlispとrubyとpythonと その4 Cライブラリの呼び出し(lisp) – テンポラリと同じもの。

呼び出し先のcで確保した領域はcontentsに入ってくるけど、元の変数にセットされない。

分かるような、納得いかないような。

p = pp.contents

で自分でセットしなおしといた。

import ctypes
from ctypes import *
so = ctypes.CDLL("./libffi-test.so")
so.f.argtypes = [c_int]
so.f.restype = c_int
def f(i):
return so.f(i)
print(f(5))
so.f0.argtypes = [c_char_p,c_int]
so.f0.restype = c_int
def f0(buf,len):
return so.f0(buf,len)
buf0 = create_string_buffer(10)
f0(buf0,10)
print(buf0.value)
so.f1.argtype = [POINTER(c_char_p)]
so.f1.restype = c_int
def f1(buf):
return so.f1(pointer(buf))
buf1 = c_char_p()
f1(buf1)
print(buf1.value)
so.f2.restype = c_char_p
def f2():
return so.f2()
print(f2())
class Person(Structure):
_fields_ = [("name",c_char_p),
("age",c_int)]
so.f3.argtype = [POINTER(c_void_p),c_int]
so.f3.restype = c_int
def f3(person):
person.name = cast(create_string_buffer(16),c_char_p)
return so.f3(pointer(person),16)
p1 = Person()
f3(p1)
print(p1.name)
print(p1.age)
so.f4.argtype = [POINTER(POINTER(c_void_p)),c_int]
so.f4.restype = c_int
def f4(person):
return so.f4(person)
p = Person()
pp = pointer(p)
ppp = pointer(pp)
f4(ppp)
print("ppp:" + ppp.contents.contents.name)
print("pp:" + pp.contents.name)
#print("p:" + p.name)
p = pp.contents
print("p:" + p.name)
#->ppp:名前いいい
#  pp:名前いいい
#  p:名前いいい

LinuxでC#を書いてみた(Mono)

2008/12/21 § コメントする

Seriesとか、Pythonのジェネレータを触っているとLINQとかと比べたくなる。

しかし家に帰ってまでWindowsを起動したくない。(IPhoneのファームを上げるとき以外は)

ならMonoでも動かしてみるか、と急に思い立った。

取り合えずUbuntuのSynapticパッケージマネージャでmonodevelopを入れる。

よくわからんがmonoの開発するっぽい名前だから。

monodevelopを入れると依存関係で他にも色々はいるみたい。けど細かいことは気にしない。

次はコンパイルの仕方と動かしかた。

コンパイラはgmcsらしい。

最初はやっぱりhello worldかなぁ。

サクッと書く。emacsでC#のコードを書くのはちょっと不思議な感じだ。

やっぱりVisual studioで書く方が楽。

//Hello.cs
using System;
public class Program
{
public static int Main(string[] args)
{
Console.WriteLine("Hello World");
return 0;
}
}

こんなソースを書いて

gmcs Hello.cs

でコンパイル。成功してHello.exeができる。

実行は

./Hello.exe

でOKみたい。

Hello World

と表示される。

さて。動作確認はとれた。

あとはどこまでできるかだ。そもそもMonoってLINQ通るんかな?(先に調べろ)

//Hello2.cs
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static int Main(string[] args)
{
var lst = new List<int>();
lst.Add(1);
lst.Add(2);
lst.Add(3);
lst.Add(4);
lst.Add(5);
var lst_gt3 = lst.Where(i => i > 3);
lst_gt3.ToList().ForEach(
i => Console.WriteLine(i));
Console.WriteLine("----------------------------");
var result = from e in lst
where e > 3
select e;
foreach(var e in result)
{
Console.WriteLine(e);
}
return 0;
}
}

というわけでLINQテスト用。

gmcs Hello2.cs

でコンパイルするとエラーはなし。

./Hello2.exe
で
4
5
----------------------------
4
5

が出力された。おお。LINQもいける。

いい感じだ。

あとは開発環境だな。なんでかわかんないけどC#はEmacsで書く気になれない。

Eclipseでも入れてみるかな・・・。

lispとrubyとpythonと その4 Cライブラリの呼び出し(まとめ)

2008/10/16 § コメントする

それぞれの言語でCと連携してみたまとめ、というか感想というか。

lispもRubyもPythonも呼び出し自体はわりと簡単。

ちゃんと動くかどうかは別として・・・。

一番すんなり理解できたのはSBCLだったような気がする。

Rubyの「拡張ライブラリをCで書く」っていうアプローチが僕にとっては新鮮だった。

CでmallocしたメモリをGCがどんな風に扱うかが気になってGCも調べた。・・・けどよくわかんない。

CommonLisp

CommonLispというか、SBCLだけど。

CのコードをLispにマッピングして書くイメージ。

sb-alien:load-shared-object

ライブラリをロード

sb-alien:define-alien-routine

C関数を呼び出すラッパを宣言

sb-alien:define-alien-type

Cの構造体に対応したデータ構造を宣言

sb-alien:with-alien

Cの変数をレキシカル変数として宣言

sb-alien:make-alien

malloc

sb-alien:free-alien

free

http://www.sbcl.org/manual/History-and-Implementation-of-SBCL.html#index-Garbage-Collection_002c-generational-2

ここ読むとSBCLは保守的GCらしい。

ということはrubyと一緒でコンパクションはしてないのかな。

Ruby

SBCLとは違って、RubyのクラスをCで作るイメージ。

C側で作ってしまえばRubyから使う方はrequire xxxとするだけなので簡単。

Cでクラスを作るときは

#include <ruby.h>

が必須

rb_define_alloc_func

newのときに呼び出される関数を登録

rb_define_private_method

rb_define_method

メソッドにあたる関数を登録

RubyのGCはmark and sweepで保守的GC。

1.9でもコンパクションはしないみたい。

Python

ctypesだとloadは

ctypes.CDLL(“xxx”)

でOKだし、呼び出しもなんとなく通るので楽。

argtype

引数のタイプを指定

restype

戻り値のタイプを指定

メモリのアロケートの仕方はなんだかよくわからない。

PythonのGCは基本が参照カウンタで、循環参照の解決にmark and sweepっぽい仕組みを使ってる。(らしい)

メモリのコンパクションをしてるのかは不明。

参考

GCについて色々見てて見つけたサイト。

保守的GCで豪快にメモリリークするケースの話。

なるほど。。。

http://practical-scheme.net/wiliki/wiliki.cgi?Gauche%3A%E3%83%A1%E3%83%A2%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%AF

GCの話が色々

http://tiki.is.os-omicron.org/tiki.cgi?c=v&p=GC

http://tiki.is.os-omicron.org/tiki.cgi?c=v&p=%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0%B8%C0%B8%EC%A4%C8GC

perlは(5.0?)

参照カウント + (スレッド終了時に)マーク・スイープなんだってさ。

lispとrubyとpythonと その4 Cライブラリの呼び出し(python)

2008/10/14 § コメントする

最後はpython。

Cとの連携方法はいくつかあるみたい(boost.pythonとかswingとか)あるみたいなんだけど、ctypesを使用。

呼び出しているcライブラリはlispとrubyとpythonと その4 Cライブラリの呼び出し(lisp) – テンポラリと同じ。

参考は、まぁここ。

http://www.python.org/doc/2.5.2/lib/module-ctypes.html

int f4(person_t** person);の呼び出しかたがわかんなかったんだけど今日はもう力尽きた・・・。

# -*- coding:utf-8 -*-
import ctypes
from ctypes import *
so = ctypes.CDLL("./libffi-test.so")
so.f.restype = c_int
def f(i):
return so.f(i)
print f(5)
so.f0.argtypes = [c_char_p,c_int]
so.f0.restype = c_int
def f0(buf,len):
return so.f0(buf,len)
buf0 = create_string_buffer(10)
print f0(buf0,10)
print buf0.value
so.f1.argtype = [POINTER(c_char_p)]
so.f1.restype = c_int
def f1(buf):
return so.f1(pointer(buf))
buf1 = c_char_p()
f1(buf1)
print buf1.value
so.f2.restype = c_char_p
def f2():
return so.f2()
print f2()
class Person(Structure):
_fields_ = [("name",c_char_p),
("age",c_int)]
so.f3.argtype = [POINTER(c_char_p),c_int]
so.f3.restype = c_int
def f3(person):
person.name = cast(create_string_buffer(16),c_char_p)
return so.f3(pointer(person),16)
p1 = Person()
f3(p1)
print p1.name
print p1.age
#so.f4.argtype = [POINTER(POINTER(Person))]
#so.f4.restype = c_int
#p2 = POINTER(POINTER(Person))
#print so.f4
#print p2
#so.f4(p2)
#so.f4(pointer(pointer(p2)))
#so.f4(p2)
#print p2.name

lispとrubyとpythonと その4 Cライブラリの呼び出し(ruby)

2008/10/14 § コメントする

つぎはruby。

rubyだとCライブラリを呼び出すというよりはrubyのクラスをCで書く感じ。

ruby1.9でためしたんだけど、1.9では

RSTRING(xxx).ptr

とか

RSTRING(xxx).len

ではなくて

RSTRING_LEN(xxx)

RSTRING_PTR(xxx)

と書くみたい。

参考はこのへん。

http://i.loveruby.net/w/RubyExtensionProgrammingGuide.html

http://wiki.livedoor.jp/aqualung/d/Ruby%a4%ce%b3%c8%c4%a5%a5%e9%a5%a4%a5%d6%a5%e9%a5%ea%a4%ce%ba%ee%a4%ea%ca%fd#content_1_5_1

でcで書いた拡張ライブラリがこんなの。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ruby.h>
typedef struct
{
VALUE prefix;
VALUE suffix;
} decorator;
void decorator_mark(decorator *p)
{
rb_gc_mark(p->prefix);
rb_gc_mark(p->suffix);
}
void decorator_free(decorator *p)
{
}
VALUE decorator_alloc(VALUE cls)
{
decorator *p = ALLOC(decorator);
return Data_Wrap_Struct(cls,decorator_mark,decorator_free,p);
}
VALUE decorator_initialize(VALUE self,VALUE prefix,VALUE suffix)
{
decorator *p;
Data_Get_Struct(self, decorator, p);
Check_Type(prefix,T_STRING);
Check_Type(suffix,T_STRING);
p->prefix = prefix;
p->suffix = suffix;
return Qnil;
}
VALUE decorator_get_string(VALUE self,VALUE str)
{
Check_Type(str,T_STRING);
decorator *p;
Data_Get_Struct(self, decorator, p);
char* buf = ALLOC_N(char,RSTRING_LEN(p->prefix) + RSTRING_LEN(str) + RSTRING_LEN(p->suffix) + 1);
memset(buf,0,RSTRING_LEN(p->prefix) + RSTRING_LEN(str) + RSTRING_LEN(p->suffix) + 1);
strncat(buf,RSTRING_PTR(p->prefix),RSTRING_LEN(p->prefix));
strncat(buf,RSTRING_PTR(str),RSTRING_LEN(str));
strncat(buf,RSTRING_PTR(p->suffix),RSTRING_LEN(p->suffix));
return rb_str_new2(buf);
}
void Init_decorator()
{
VALUE d;
d = rb_define_class("Decorator", rb_cObject);
rb_define_alloc_func(d, decorator_alloc);
rb_define_private_method(d, "initialize", decorator_initialize, 2);
rb_define_method(d, "get_string", decorator_get_string, 1);
}

で、こんな感じのスクリプトを実行

ruby -r mkmf -e 'create_makefile("decorator")'
make # ruby

実行するとmakeまで走ってdecorator.soができる。

rubyからの呼び出しはこんな感じ。

require 'decorator.so'
d = Decorator.new "start:" , ":end"
puts d.get_string("aaa")

lispとrubyとpythonと その4 Cライブラリの呼び出し(lisp)

2008/10/14 § コメントする

今回はCライブラリの呼び出し。

SBCL限定なので注意。

sb-alienにCを呼び出すために必要なもろもろが入ってる。

一応動いてるんだけど、これであってんのかなぁ。

C側でmallocした時とか、GCのコンパクションでまずいことになったりしないんだろうか・・・。

参考はここ。

http://www.sbcl.org/manual/Foreign-Function-Interface.html#Foreign-Function-Interface

まず、呼び出すcのライブラリはこんなの。

ffi-test.h

int f(int i);
int f0(char* buf,int len);
int f1(char** buf);
char* f2();
typedef struct person{
char* name;
int age;
} person_t;
int f3(person_t* person,int len);
int f4(person_t** person);

実装はこちら。

ffi-test.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ffi-test.h"
int f(int i)
{
return i + 1;
}
//呼び出し元でAlloc
int f0(char* buf,int len)
{
printf("hello\n");
strncpy(buf,"日本語\n",len);
return 0;
}
//関数内でAlloc
int f1(char** buf)
{
int sz = sizeof(char) * 64;
*buf =(char*) malloc(sz);
strncpy(*buf,"日本語2\n",sizeof(char) * 64);
return 0;
}
//戻り値で返してみる
char* f2()
{
int sz = sizeof(char) * 64;
char* buf =(char*) malloc(sz);
strncpy(buf,"日本語3\n",sizeof(char) * 64);
return buf;
}
//構造体 呼び出し元でAlloc
int f3(person_t* person,int len)
{
strncpy(person->name,"名前あああ",len);
person->age = 30;
return 0;
}
//構造体 関数内でAlloc
int f4(person_t** person)
{
int sz1 = sizeof(person_t);
*person = (person_t*)malloc(sz1);
int sz2 = sizeof(char) * 64;
(*person)->name = malloc(sz2);
strncpy((*person)->name,"名前いいい",sz2);
(*person)->age = 40;
return 0;
}

んで、これを

gcc -shared ffitest.c -o libffi-test.so

でコンパイル。

呼び出すlisp側はこんな感じ。

define-alien-routineでcライブラリとのラッパを宣言。

make-alienがmallocでfree-alienがfree。

(load-shared-object "libffi-test.so")
(declaim (inline f))
(sb-alien:define-alien-routine f
sb-alien:int
(i sb-alien:int))
(declaim (inline f0))
(sb-alien:define-alien-routine f0
sb-alien:int
(buf (sb-alien:* sb-alien:char))
(len sb-alien:int))
(declaim (inline f1))
(sb-alien:define-alien-routine f1
sb-alien:int
(buf (sb-alien:* (sb-alien:c-string :external-format :utf8))))
(declaim (inline f2))
(sb-alien:define-alien-routine f2
sb-alien:c-string)
(sb-alien:define-alien-type person_t
(sb-alien:struct person
(name (sb-alien:* sb-alien:char))
(age int)))
(declaim (inline f3))
(sb-alien:define-alien-routine f3
sb-alien:int
(person (sb-alien:* person_t))
(len sb-alien:int))
(declaim (inline f4))
(sb-alien:define-alien-routine f4
sb-alien:int
(buf (sb-alien:* (sb-alien:* person_t))))
(defun lisp-f0()
(sb-alien:with-alien ((len sb-alien:int (* (sb-alien:alien-size sb-alien:char) 64))
(buf (sb-alien:* sb-alien:char) (sb-alien:make-alien sb-alien:char len)))
(unwind-protect
(sb-alien:with-alien ((status sb-alien:int (f0 buf len))
(rtn (sb-alien:c-string :external-format :utf8) buf))
rtn)
(sb-alien:free-alien buf))))
(defun lisp-f1()
(sb-alien:with-alien ((buf (sb-alien:c-string :external-format :utf8)))
(sb-alien:with-alien ((rtn sb-alien:int (f1 (sb-alien:addr buf))))
buf)))
(defun lisp-f2()
(sb-alien:with-alien ((buf (sb-alien:c-string :external-format :utf8) (f2)))
buf))
(defun lisp-f3()
(sb-alien:with-alien ((len sb-alien:int (* (sb-alien:alien-size sb-alien:char) 64))
(p
(sb-alien:* person_t)
(sb-alien:make-alien person_t 1)))
(unwind-protect
(progn
(setf (slot p 'name) (sb-alien:make-alien sb-alien:char len))
(unwind-protect
(sb-alien:with-alien ((status sb-alien:int (f3 p len))
(rtn (sb-alien:c-string :external-format :utf8) (slot p 'name)))
rtn)
(sb-alien:free-alien (slot p 'name))))
(sb-alien:free-alien p))))
(defun lisp-f4()
(sb-alien:with-alien ((p (sb-alien:* person_t))
(status sb-alien:int (f4 (sb-alien:addr p)))
(rtn (sb-alien:c-string :external-format :utf8) (slot p 'name)))
rtn))

で呼び出し結果がこれ。

CL-USER> (lisp-f0)
"日本語
"
CL-USER> (lisp-f1)
"日本語2
"
CL-USER> (lisp-f2)
"日本語3
"
CL-USER> (lisp-f3)
"名前あああ"
CL-USER> (lisp-f4)
"名前いいい"

Yコンビネータができるまで(C#)

2008/09/22 § コメントする

Yコンビネータ復習 – テンポラリをC#で書いてみた。

再起呼び出しをちょびちょび書き換えるので結構長編です。

C#だと静的型なので自己呼び出しするdelegateが必要。

&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate int sum_delegate(int n);
delegate sum_delegate fun_delegate(fun_delegate f);
static void Main(string[] args)
{
int i = Fun(3);
Console.WriteLine(i);
Console.ReadKey();
}
static int Fun(int n)
{
if (n == 0)
{
return 0;
}
else
{
return n + Fun(n - 1);
}
}
}
}

こんな感じの再帰関数をYコンビネータっぽいのを使って書き直す。

まずは再起呼び出しのFunを外からパラメータとして受け取るようにする。

&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate FUNC SelfCaller<FUNC>(SelfCaller<FUNC> f);
static void Main(string[] args)
{
int i = Fun(Fun)(3);
Console.WriteLine(i);
Console.ReadKey();
}
static Func<int, int> Fun(SelfCaller<Func<int, int>> fun)
{
return delegate(int n)
{
if (n == 0)
{
return 0;
}
else
{
return n + fun(fun)(n - 1);
}
};
}
}
}

こうなった。

つぎにFunをMakeFunに変えて、MakeFunを呼び出すラッパをFunにする。

&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate FUNC SelfCaller<FUNC>(SelfCaller<FUNC> f);
static void Main(string[] args)
{
int i = Fun()(3);
Console.WriteLine(i);
Console.ReadKey();
}
static Func<int, int> Fun()
{
return MakeFun(MakeFun);
}
static Func<int, int> MakeFun(SelfCaller<Func<int, int>> fun)
{
return delegate(int n)
{
if (n == 0)
{
return 0;
}
else
{
return n + fun(fun)(n - 1);
}
};
}
}
}

fun(fun)(n – 1)部分を切り出す。

&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate FUNC SelfCaller<FUNC>(SelfCaller<FUNC> f);
static void Main(string[] args)
{
int i = Fun()(3);
Console.WriteLine(i);
Console.ReadKey();
}
static Func<int, int> Fun()
{
return MakeFun(MakeFun);
}
static Func<int, int> MakeFun(SelfCaller<Func<int, int>> fun)
{
return delegate(int n)
{
Func<int, int> imple = delegate(int m)
{
return fun(fun)(m);
};
if (n == 0)
{
return 0;
}
else
{
return n + imple(n - 1);
}
};
}
}
}
||>
実処理を外から受けとるようにする。
static Func<int, int> Imple(Func<int, int> fun)が実際の処理。
>|cs|
&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate FUNC SelfCaller<FUNC>(SelfCaller<FUNC> f);
static void Main(string[] args)
{
int i = Fun()(3);
Console.WriteLine(i);
Console.ReadKey();
}
static Func<int, int> Fun()
{
return MakeSelfCaller(Imple)(MakeSelfCaller(Imple));
}
static SelfCaller<Func<int, int>> MakeSelfCaller(Func<Func<int, int>, Func<int, int>> imple)
{
return delegate(SelfCaller<Func<int, int>> caller)
{
Func<int, int> makeFun = delegate(int m)
{
return caller(caller)(m);
};
return imple(makeFun);
};
}
static Func<int, int> Imple(Func<int, int> fun)
{
return delegate(int n)
{
if (n == 0)
{
return 0;
}
else
{
return n + fun(n - 1);
}
};
}
}
}

FunがImpleをとるようにして、FunをYに改名。

&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate FUNC SelfCaller<FUNC>(SelfCaller<FUNC> f);
static void Main(string[] args)
{
int i = Y(Imple)(3);
Console.WriteLine(i);
Console.ReadKey();
}
static Func<int, int> Y(Func<Func<int,int>,Func<int,int>> imple)
{
return MakeSelfCaller(imple)(MakeSelfCaller(imple));
}
static SelfCaller<Func<int, int>> MakeSelfCaller(Func<Func<int, int>, Func<int, int>> imple)
{
return delegate(SelfCaller<Func<int, int>> caller)
{
Func<int, int> makeFun = delegate(int m)
{
return caller(caller)(m);
};
return imple(makeFun);
};
}
static Func<int, int> Imple(Func<int, int> fun)
{
return delegate(int n)
{
if (n == 0)
{
return 0;
}
else
{
return n + fun(n - 1);
}
};
}
}
}

SelfCallerをインラインに展開してしまう。

&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate FUNC SelfCaller<FUNC>(SelfCaller<FUNC> f);
static void Main(string[] args)
{
int i = Y(Imple)(3);
Console.WriteLine(i);
Console.ReadKey();
}
static Func<int, int> Y(Func<Func<int, int>, Func<int, int>> imple)
{
Func<Func<Func<int, int>, Func<int, int>>, SelfCaller<Func<int, int>>> caller =
delegate(Func<Func<int, int>, Func<int, int>> prmImple)
{
return delegate(SelfCaller<Func<int, int>> prmCaller)
{
Func<int, int> makeFun = delegate(int m)
{
return prmCaller(prmCaller)(m);
};
return prmImple(makeFun);
};
};
return caller(imple)(caller(imple));
}
static Func<int, int> Imple(Func<int, int> fun)
{
return delegate(int n)
{
if (n == 0)
{
return 0;
}
else
{
return n + fun(n - 1);
}
};
}
}
}

Impleは消しちゃって、Lambda式を受けとるように変更。

&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate FUNC SelfCaller<FUNC>(SelfCaller<FUNC> f);
static void Main(string[] args)
{
int i = Y(f => n =>
{
if (n == 0)
{
return 0;
}
else
{
return n + f(n - 1);
}
})(3);
Console.WriteLine(i);
Console.ReadKey();
}
static Func<int, int> Y(Func<Func<int, int>, Func<int, int>> imple)
{
Func<Func<Func<int, int>, Func<int, int>>, SelfCaller<Func<int, int>>> caller =
delegate(Func<Func<int, int>, Func<int, int>> prmImple)
{
return delegate(SelfCaller<Func<int, int>> prmCaller)
{
Func<int, int> makeFun = delegate(int m)
{
return prmCaller(prmCaller)(m);
};
return prmImple(makeFun);
};
};
return caller(imple)(caller(imple));
}
}
}

intにしてた型をT、TResultに戻す。

&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate FUNC SelfCaller<FUNC>(SelfCaller<FUNC> f);
static void Main(string[] args)
{
int i = Y<int,int>(f => n =>
{
if (n == 0)
{
return 0;
}
else
{
return n + f(n - 1);
}
})(3);
Console.WriteLine(i);
Console.ReadKey();
}
static Func<T, TResult> Y<T, TResult>(Func<Func<T, TResult>, Func<T, TResult>> imple)
{
Func<Func<Func<T, TResult>, Func<T, TResult>>, SelfCaller<Func<T, TResult>>> caller =
delegate(Func<Func<T, TResult>, Func<T, TResult>> prmImple)
{
return delegate(SelfCaller<Func<T, TResult>> prmCaller)
{
Func<T, TResult> makeFun = delegate(T m)
{
return prmCaller(prmCaller)(m);
};
return prmImple(makeFun);
};
};
return caller(imple)(caller(imple));
}
}
}

あとはちょこちょこと整える。

わかりやすいようにdelegateで書いてる部分をLambdaに置き換えていく。

最終的にはこんな感じ。

&#65279;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Y
{
class Program
{
delegate FUNC SelfCaller<FUNC>(SelfCaller<FUNC> f);
static void Main(string[] args)
{
string s1 = Y<int,string>(f => n =>
{
if (n == 0)
{
return "0";
}
else
{
return n.ToString() + f(n - 1);
}
})(3);
Console.WriteLine(s1);
string s2 = Y<int, int, string>(f => (n, m) =>
{
if (n == 0)
{
return "0";
}
else
{
return n.ToString() + ":" + m + ":" + f(n - 1, m);
}
})(3, 4);
Console.WriteLine(s2);
Console.ReadKey();
}
static Func<T, TResult> Y<T, TResult>(Func<Func<T, TResult>, Func<T, TResult>> imple)
{
Func<Func<Func<T, TResult>, Func<T, TResult>>, SelfCaller<Func<T, TResult>>> caller =
prmImple => prmCaller => prmImple(m => prmCaller(prmCaller)(m));
return caller(imple)(caller(imple));
}
static Func<T1, T2, TResult> Y<T1, T2, TResult>(Func<Func<T1, T2, TResult>, Func<T1, T2, TResult>> imple)
{
Func<Func<Func<T1, T2, TResult>, Func<T1, T2, TResult>>, SelfCaller<Func<T1, T2, TResult>>> caller =
prmImple => prmCaller => prmImple((a,b) => prmCaller(prmCaller)(a,b));
return caller(imple)(caller(imple));
}
}
}

LINQで非決定性計算

2008/09/11 § コメントする

Haskellやっぱ難しいよ。難しいって。 – テンポラリ

↑前にhaskellでやってたのをC# + LINQでやってみた。

前は意味わかんなかったけど、今なら読めるしかけるなぁ。

public void f1()
{
var result =
from baker in Enumerable.Range(1, 5)
from cooper in Enumerable.Range(1, 5)
from fletcher in Enumerable.Range(1, 5)
from miller in Enumerable.Range(1, 5)
from smith in Enumerable.Range(1, 5)
where !new[] { baker, cooper, fletcher, miller, smith }.Dup()
&& baker != 5
&& cooper != 1
&& fletcher != 1 && fletcher != 5
&& miller > cooper
&& Math.Abs(smith - fletcher) != 1
&& Math.Abs(fletcher - cooper) != 1
select new { baker = baker, cooper = cooper, fletcher = fletcher, miller = miller, smith = smith };
result.ToList().ForEach(
r => Console.WriteLine(
"baker:{0} cooper:{1} fletcher:{2} miller:{3} smith:{4}",
r.baker,
r.cooper,
r.fletcher,
r.miller,
r.smith));
}
ユーティリティがコレ
public static class Util
{
public static bool Dup(this int[] values)
{
return values.Distinct().Count() != values.Length;
}
}
メソッドで書くとこんな感じ?
public void f2()
{
var result =
Enumerable.Range(1, 5).SelectMany(
baker => Enumerable.Range(1, 5).SelectMany(
cooper => Enumerable.Range(1, 5).SelectMany(
fletcher => Enumerable.Range(1, 5).SelectMany(
miller => Enumerable.Range(1, 5).SelectMany(
smith => Enumerable.Repeat(new
{
baker = baker,
cooper = cooper,
fletcher = fletcher,
miller = miller,
smith = smith
}, 1)))))).Where(
r => !new[] { r.baker, r.cooper, r.fletcher, r.miller, r.smith }.Dup()
&& r.baker != 5
&& r.cooper != 1
&& r.fletcher != 1
&& r.fletcher != 5
&& r.miller > r.cooper
&& Math.Abs(r.smith - r.fletcher) != 1
&& Math.Abs(r.fletcher - r.cooper) != 1);
result.ToList().ForEach(
r => Console.WriteLine(
"baker:{0} cooper:{1} fletcher:{2} miller:{3} smith:{4}",
r.baker,
r.cooper,
r.fletcher,
r.miller,
r.smith));
}

SQLServer2005 バルクコピー

2008/04/29 § コメントする

メモ。

でかいサイズのデータを高速コピー。

http://msdn2.microsoft.com/ja-jp/library/7ek5da1a(VS.80).aspx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Data.Sql;
using System.Data.SqlClient;
namespace BulkCopy
{
class Program
{
static void Main(string[] args)
{
//Exec_Datatable();
Exec_Datareader();
}
static void Exec_Datareader()
{
var con = new SqlConnection(@"Data Source=xxx\sqlexpress;Initial Catalog=LockTest;Integrated Security=True");
con.Open();
var cmd = new SqlCommand("select * from tb2", con);
var dr = cmd.ExecuteReader();
var sbc = new SqlBulkCopy("Data Source=xxx;Initial Catalog=Test;Integrated Security=True");
sbc.DestinationTableName = "tb0";
sbc.ColumnMappings.Add(
new SqlBulkCopyColumnMapping(
"cd_",
"cd"));
sbc.ColumnMappings.Add(
new SqlBulkCopyColumnMapping(
"data1_",
"data1"));
sbc.ColumnMappings.Add(
new SqlBulkCopyColumnMapping(
"data2_",
"data2"));
sbc.WriteToServer(dr);
}
static void Exec_Datatable()
{
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
var da = new LocktestTableAdapters.tb2TableAdapter();
var dt = da.GetData();
var sbc = new SqlBulkCopy("Data Source=xxx;Initial Catalog=Test;Integrated Security=True");
sbc.DestinationTableName = "tb0";
sbc.ColumnMappings.Add(
new SqlBulkCopyColumnMapping(
"cd_",
"cd"));
sbc.ColumnMappings.Add(
new SqlBulkCopyColumnMapping(
"data1_",
"data1"));
sbc.ColumnMappings.Add(
new SqlBulkCopyColumnMapping(
"data2_",
"data2"));
sbc.WriteToServer(dt);
scope.Complete();
}
}
}
}

Where Am I?

日記C# カテゴリーを表示中です。