crossframe » Haskell http://crossframe.iiv.jp Windows Dev. Site Tue, 07 Nov 2023 06:31:52 +0000 ja hourly 1 https://wordpress.org/?v=3.8.41 Haskell from C# ../../../20140309714/ ../../../20140309714/#comments Sat, 08 Mar 2014 15:20:21 +0000 http://xfra.me/?p=714 Haskell from Excel という過去の投稿で、C++からのHaskell呼び出しをやりましたが、C#から直接できることを以下のサイトで知り、テストしてみました。

Calling Haskell from C#

http://stackoverflow.com/questions/16615641/calling-haskell-from-c-sharp

このサイトでは、Monoで実行していますが、Windowsでテストしました。
また、Stringを戻り値とする関数が使いたかったので、これを追加しています。

環境: GHC ver 7.6.3, VisualStudio 2010 / Windows 7
Foo.hs

module Foo where

import Foreign.C.String
import Foreign.C.Types
import Data.List.Split

foo :: CString -> IO CInt
foo c_str = do
	str    <- peekCString c_str
	result <- hs_foo str 
	return $ fromIntegral result

hs_foo :: String -> IO Int
hs_foo str = do
	putStrLn str
	return (length str)

hstest :: CString -> IO CString
hstest c_str = do
	str <- peekCString c_str
	let s = concat $ fmap cadd $ chunksOf 1 str
	newCString s

cadd :: String -> String
cadd c = do
	c ++ " "

foreign export ccall foo :: CString -> IO CInt
foreign export ccall hstest :: CString -> IO CString

ghc -no-hs-main -shared -o Foo.so Foo.hs

hstestで、C文字列をHaskell文字列に変換し、文字列操作をして、またC文字列に戻しています。

次にC#側ですが、VisualStudioのC#コンソールアプリケーションプロジェクトで作成します。
Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace csConsoleHaskell01
{
	class Program
	{
		[DllImport("Foo.so", CallingConvention = CallingConvention.Cdecl)]
		private static extern void hs_init(IntPtr argc, IntPtr argv);

		[DllImport("Foo.so", CallingConvention = CallingConvention.Cdecl)]
		private static extern void hs_exit();

		[DllImport("Foo.so", CallingConvention = CallingConvention.Cdecl)]
		private static extern int foo(string str);

		[DllImport("Foo.so", CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr hstest(string str);

		static void Main(string[] args)
		{
			hs_init(IntPtr.Zero, IntPtr.Zero);

			int result = foo("Hello!");
			Console.WriteLine("Length : {0}", result);

			IntPtr r = hstest("Hello_Haskell_String");
			string s = Marshal.PtrToStringAnsi(r);
			Console.WriteLine(s);

			hs_exit();
		}
	}
}

intを戻すときは、そのままでしたが、stringは上のようにポインタを取得してから変換する必要があるようです。(戻り値stringは不可)
Haskell Foo.soをcsConsoleHaskell01\bin\Debugディレクトリにおいて、csConsoleHaskell01.exeをコマンドプロンプトで実行します。

Hello!
Length : 6
H e l l o _ H a s k e l l _ S t r i n g

このように表示されます。
.NetとHaskellを結びつけるには、HaskellのFFI(ForeignFunctionInterface)を使ってC++/CLIとリンクして、さらに.Netマネージコードと連携しなくてはいけないと思っていましたが、このように簡単にできてしまうのですね。C#-Haskellができると、ここからいろいろと派生できそうです。

]]>
../../../20140309714/feed/ 0
QtとHaskell/VisualStudio ../../../20131124638/ ../../../20131124638/#comments Sat, 23 Nov 2013 15:04:32 +0000 http://xfra.me/?p=638 QtとHaskellは、どちらもソースコンパチブルでクロスプラットフォームの対応ができることから、実行環境について類似点があると思っています。またQtはC++、HaskellはFFI(Foreign Function Interface)によりC言語との親和性がとても高く、長年Cに慣れてきた自分にとって、この二つはとても肌に合う技術です。

JavaVMや.NET(Mono)の中間言語、Python等の軽量言語でクロスプラットフォーム開発をする方法もいいですが、Cでも古くない(やれることが新しい言語に負けていない)という点が魅力に感じます。
QtはUI、Haskellはロジックという使い方で、いろいろやってみたいことがあり、まず最初に、Hakellの関数の戻り値をQWebViewに表示してみることにしました。(WebViewに、ということは、JavaScriptとの連携ができることを意図しています。) QWebviewは以前「QtWebKit.QWebView を使ったPython、JavaScript連携」でテストしましたが、今度はQtがメインでVisualStudioでビルドしました。

環境

Glasgow Haskell Compiler, Version 7.6.3 stage 2 booted by GHC version 7.4.

Qt 5.1.1 for Windows 32-bit
qt-windows-opensource-5.1.1-msvc2010-x86-offline.exe

Visual Studio Add-in 1.2.2 for Qt5
qt-vs-addin-1.2.2-opensource.exe

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) void __stdcall HsBegin(void);
__declspec(dllexport) void __stdcall HsEnd(void);
__declspec(dllexport) long __stdcall adder(long x, long y);
#ifdef __cplusplus
}
#endif

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
	ui->webView->load(QUrl("file:///c:/test.html"));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_1_clicked()
{
  char buf[20];

    HsBegin();
    sprintf_s(buf, "adder : %d", adder(1,2));
    HsEnd();

    ui->webView->page()->mainFrame()->findFirstElement("body").appendInside(buf);
}

Haskellコードは「Haskell from Excel」を参考にしてください。

プログラムを起動するとtest.htmlが読み込まれ、ボタンを押すとエリアに演算結果が追加されます。
実はこのプログラムは、いきなりVisualStudioで作成したのではなく、QtCreator 2.8.1(Baseed on Qt 5.1.1 MSVC 2010.32bit)で作成したものを、Qt5Add-Inを組み込んだVisualStudioで読み込みました。
Qt Creator
QtCreator

Visual Studio Add-in 1.2.2 for Qt5 (Open Qt Project File(.pro))
Qt4AddIn

もちろんQt Creatorだけでも開発可能ですが、Add-InのテストをするためVSを使用しました。
Haskellをメインに、Qtを使うこともできるようですが、私の環境では、ghcで使われているmingwと、Qtで使われるmingwのバージョンが違うせいか、実行時にエラーとなりました。
なかなか思い通りになってくれないものですね。

]]>
../../../20131124638/feed/ 0
Haskell from Excel ../../../20131103582/ ../../../20131103582/#comments Sun, 03 Nov 2013 14:27:02 +0000 http://xfra.me/?p=582 HaskellのモジュールをExcelから呼び出す方法がかかれたBlogをみつけたので、実際に自分の環境でやってみました。

Calling Haskell from Excel

http://flxldn.tumblr.com/post/163596541/calling-haskell-from-excel

しかし環境が違うためか、残念ながらできませんでした。せっかくなので覚えとして書きたいと思います。
(いろいろやってみてXLLアドインの勉強にはありましたが・・)

C++からHaskellの呼び出し、ExcelからのC++(XLL)呼び出しはできますが、つなげると以下のようなアラートがでました。
xllError
XLLは、xlw(A Wrapper for the Excel API)を使う方法と、Excel 2010 XLL SDKを使う方法と、二通りやりました。

参考)
xlw :

http://xlw.sourceforge.net/

http://d.hatena.ne.jp/teramonagi/20110124/1295866787

xll sdk:

http://www.microsoft.com/en-us/download/details.aspx?id=20199

テスト環境 Excel 2010 + xlw ver5, Visual Studio 2010 / Windows 7

まずHaskellソースからDLLを作成します。
addr.hs

module Adder where 

adder :: Int -> Int -> IO Int --gratuitous use of IO 
adder x y = return (x+y) 

foreign export stdcall adder :: Int -> Int -> IO Int

adder.h

#ifdef __cplusplus
extern “C”
{
#endif
__declspec(dllexport) void __stdcall HsBegin(void);
__declspec(dllexport) void __stdcall HsEnd(void);
__declspec(dllexport) long __stdcall adder(long x, long y);
#ifdef __cplusplus
}
#endif

adder.def

LIBRARY Adder
EXPORTS
adder@8=_adder
HsBegin@0=_HsBegin
HsEnd@0=_HsEnd

dllMain.c

static char* args[] = {"ghcDll" , NULL };

BOOL STDCALL DllMain( HANDLE hModule, DWORD reason, void* reserved)
{  return TRUE;}
__stdcall void HsBegin()
{
startupHaskell(1, args, __stginit_Adder);
}
__stdcall void HsEnd()
{
hs_exit();
}

以下コンパイル手順です。(VisualStudio2010コマンドプロンプト)

ghc -static -c adder.hs -fglasgow-exts
ghc -static -c dllMain.c
ghc -static -shared -o adder.dll adder.o adder_stub.o dllMain.o
lib /MACHINE:x86 /DEF:adder.def /OUT:adder.lib /NOLOGO /SUBSYSTEM:WINDOWS

出力されたadder.dllはSystem32フォルダにコピーします。

次に、XLLファイルを作成します。
xlwのインストールディレクトリの中にあるxlwTemplateExtractor.exe実行すると、XLL_Projectというフォルダがマイドキュメントに作成されるので、ここにあるソリューションを開きます。
デフォルトのEchoShortの下に追加して以下のようになります。

#include<cppinterface.h>

#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) void __stdcall HsBegin(void);
__declspec(dllexport) void __stdcall HsEnd(void);
__declspec(dllexport) long __stdcall adder(long x, long y);
#ifdef __cplusplus
}
#endif

#pragma warning (disable : 4996)

short // echoes a short
EchoShort(short x // number to be echoed
           )
{
    return x;
}

short funcAdd(short d1, short d2){
 return adder(d1, d2);
//return d1 + d2;
}

cppinterface.hにはfuncAddのプロトタイプを追加します。
xlwWrapper.cppというソースは自動で生成されるようです。
adder.libを参照するようにします。

まずコメントしてあるd1+d2で成功したことを確認してから、adderのテストしました。
すると上記アラートがでます。
ここで、HsBegin、HsEndを使い方を元のブログを見てみると、ライブラリ自体のmakeが必要のようだったのであきらめ、次にXLL SDKをテストしました。(ライブラリを変更してもたぶん結果は同じという気もしましたし)

XLL SDKをインストールしたフォルダ内にある、EXAMPLEプロジェクトを使用します。
他の関数を参考にして、


#define rgFuncsRows 30

static LPWSTR rgFuncs[rgFuncsRows][7] = {

....
	{L"CalcCircum",					L"BB", L"CalcCircum"},
	{L"funcAdd",					L"III", L"funcAdd"}
};

....
__declspec(dllexport) double WINAPI CalcCircum(double pdRadius)
{
	return pdRadius * 6.283185308;
}
__declspec(dllexport) short WINAPI funcAdd(short x, short y)
{
	return (short)adder((long)x,(long)y);
	//return x + y;
}

このソースのxAutoOpen()、xAutoClose()にそれぞれHsBegin()、HsEnd()を追加。これらとadderの宣言部もxlwと同様に追加。

これもreturn x+yで動作確認後、Haskell呼び出し部をテストしました。それで上記アラートが出ました。
Excel-DNAてadder.dllを、とも思いましたが、あれはマネージDLLでした。
成果が何もないのもなんなので、cppコンソールアプリでHaskell呼び出しをしてみました。(adder.dllはexeと同じところに置く)

#include "stdafx.h"

#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) void __stdcall HsBegin(void);
__declspec(dllexport) void __stdcall HsEnd(void);
__declspec(dllexport) long __stdcall adder(long x, long y);
#ifdef __cplusplus
}
#endif

int _tmain(int argc, _TCHAR* argv[])
{
	HsBegin();
	printf("adder : %d\n", adder(1,2));	
	HsEnd();	
	getchar();
	return 0;
}

3 を表示します。

また解決したらつづきを書きたいと思います。

]]>
../../../20131103582/feed/ 0
Haskell / Windows ../../../20130830402/ ../../../20130830402/#comments Fri, 30 Aug 2013 14:44:42 +0000 http://xfra.me/?p=402 Haskellは以前勉強しましたが、使うことがないこともあってまったく身に付きませんでした。関数型言語はF#を学習中ですが、いろいろと勉強しているとHaskellに関するサンプルや情報が多いことを感じ、すぐテストできる環境を用意しておいた方がいいと思い、セットアップしてみました。

http://neue.cc/2010/01/04_233.html

このサイトをみると、IDEにはLeksahがよさそうだ、ということでインストールしてみました。
Leksahの前に、Haskell Platformをインストールする必要があります。
HaskellコンパイラGHCのバージョンは、7.6.3ですが、leksah-0.12.0.3-ghc-7.4.1.exe(これが最新なので)を使いました。

Leksahを起動後、Package->Newから、Create Folderでフォルダを作りますが、これがイコールプロジェクト名となります。フォルダを作成してOpenすると、Package設定がでてくるので、Executablesを選択して、ExecutableNameをクリックしてSaveします。
Lekp

デフォルトで以下のような、”Hello World”を表示するだけのサンプルコードが生成されるので、これを
- Configures the package
- Builds the package
- Runs the package
と順に、ツールバーから実行します。するとLog Windowに”Hello World”が表示されます。
hcode

これでとりあえず動作確認をしておいて、目的のプログラムを動かしてみます。
ファイルコンバータ的なものをつくることが多くなりそうなので、大文字変換するものを試してみました。
Lek0s
あとエディタの面白い機能として、カスタム文字への変換があります。
Configuration->To Candyチェックボックスで、以下の表示切替をできます。

Lek1s

Lek2s

こういうのマニア心をくすぐりますね。ソースは、O’REILLYの”Real World Haskell”から引用しました。
欲を言えば、neueccさんのサイトにあるVisual Haskellのようなものが使えれば、とも期待もしたのですが(VisualStudioで他の言語とリンクできたりできるなどなど)、無理っほいのでここまでとなりました。

]]>
../../../20130830402/feed/ 0