gpt4 book ai didi

haskell - Haskell 中的 OCaml 仿函数(参数化模块)仿真

转载 作者:行者123 更新时间:2023-12-03 14:07:51 25 4
gpt4 key购买 nike

有没有推荐的方法来使用类型类来模拟类似 OCaml 的参数化模块?

例如,我需要实现复杂的模块
通用计算,可以用不同的参数化
杂项类型,功能等。更具体地说,让它成为
可以用不同参数化的 kMeans 实现
值的类型、向量类型(列表、未装箱的向量、向量、元组等),
和距离计算策略。

为方便起见,为了避免大量中间类型,我想
通过 DataSet 类具有此计算多态性,其中包含所有
所需的接口(interface)。我也尝试使用 TypeFamilies 来避免很多
类型类参数(也会导致问题):

{-# Language MultiParamTypeClasses
, TypeFamilies
, FlexibleContexts
, FlexibleInstances
, EmptyDataDecls
, FunctionalDependencies
#-}

module Main where

import qualified Data.List as L
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as U

import Distances
-- contains instances for Euclid distance
-- import Distances.Euclid as E
-- contains instances for Kulback-Leibler "distance"
-- import Distances.Kullback as K

class ( Num (Elem c)
, Ord (TLabel c)
, WithDistance (TVect c) (Elem c)
, WithDistance (TBoxType c) (Elem c)
)
=> DataSet c where
type Elem c :: *
type TLabel c :: *
type TVect c :: * -> *
data TDistType c :: *
data TObservation c :: *
data TBoxType c :: * -> *
observations :: c -> [TObservation c]
measurements :: TObservation c -> [Elem c]
label :: TObservation c -> TLabel c
distance :: TBoxType c (Elem c) -> TBoxType c (Elem c) -> Elem c
distance = distance_

instance DataSet () where
type Elem () = Float
type TLabel () = Int
data TObservation () = TObservationUnit [Float]
data TDistType ()
type TVect () = V.Vector
data TBoxType () v = VectorBox (V.Vector v)
observations () = replicate 10 (TObservationUnit [0,0,0,0])
measurements (TObservationUnit xs) = xs
label (TObservationUnit _) = 111

kMeans :: ( Floating (Elem c)
, DataSet c
) => c
-> [TObservation c]
kMeans s = undefined -- here the implementation
where
labels = map label (observations s)
www = L.map (V.fromList.measurements) (observations s)
zzz = L.zipWith distance_ www www
wtf1 = L.foldl wtf2 0 (observations s)
wtf2 acc xs = acc + L.sum (measurements xs)
qq = V.fromList [1,2,3 :: Float]
l = distance (VectorBox qq) (VectorBox qq)

instance Floating a => WithDistance (TBoxType ()) a where
distance_ xs ys = undefined

instance Floating a => WithDistance V.Vector a where
distance_ xs ys = sqrt $ V.sum (V.zipWith (\x y -> (x+y)**2) xs ys)

这段代码以某种方式编译和工作,但它非常丑陋和hacky。

kMeans 应该通过值类型(数字、浮点数、任何东西)进行参数化,
box类型(vector,list,unboxed vector, tuple都可以)和距离计算策略。

还有 Observation 的类型(这是用户提供的样本类型,
应该有很多,每个观察中都包含测量值)。

所以问题是:

1) 如果函数的签名中不包含参数类型,
不会推断类型

2)仍然不知道,如何声明类型类 WithDistance 具有不同的实例
对于不同的距离类型(Euclid,Kullback,任何其他通过幻像类型)。

现在 WithDistance 只是通过盒子类型和值类型多态的,所以如果我们需要
不同的策略,我们可能只将它们放在不同的模块中并导入所需的
模块。但这是一种 hack 和非类型化的方法,对吧?

所有这些都可以在 OCaml 中通过 is't 模块轻松完成。什么是正确的方法
在 Haskell 中实现这样的事情?

具有 TypeFamilies 的类型类在某种程度上看起来类似于参数模块,但它们
工作不同。我真的需要这样的东西。

最佳答案

Haskell 确实缺乏在 *ML 模块系统中发现的有用功能。
正在努力扩展 Haskell 的模块系统:http://plv.mpi-sws.org/backpack/

但我认为如果没有这些 ML 模块,你可以走得更远。
您的设计遵循 God class反模式,这就是为什么它是反模块化的。

类型类只有在每个类型只能有该类的一个实例时才有用。例如。 DataSet ()实例修复 type TVect () = V.Vector你不能轻易地创建类似的实例,但使用 TVect = U.Vector .

您需要从实现 kMeans 开始函数,然后通过用类型变量替换具体类型并在需要时用类型类约束这些类​​型变量来概括它。

这是一个小例子。起初你有一些非一般的实现:

kMeans :: Int -> [(Double,Double)] -> [[(Double,Double)]]
kMeans k points = ...

然后你通过距离计算策略来概括它:
kMeans
:: Int
-> ((Double,Double) -> (Double,Double) -> Double)
-> [(Double,Double)]
-> [[(Double,Double)]]
kMeans k distance points = ...

现在您可以按点的类型对其进行概括,但这需要引入一个类,该类将捕获距离计算使用的点的某些属性,例如获取坐标列表:
kMeans
:: Point p
=> Int -> (p -> p -> Coord p) -> [p]
-> [[p]]
kMeans k distance points = ...

class Num (Coord p) => Point p where
type Coord p
coords :: p -> [Coord p]

euclidianDistance
:: (Point p, Floating (Coord p))
=> p -> p -> Coord p
euclidianDistance a b
= sum $ map (**2) $ zipWith (-) (coords a) (coords b)

现在您可能希望通过用向量替换列表来加快速度:
kMeans
:: (Point p, DataSet vec p)
=> Int -> (p -> p -> Coord p) -> vec p
-> [vec p]
kMeans k distance points = ...

class DataSet vec p where
map :: ...
foldl' :: ...

instance Unbox p => DataSet U.Vector p where
map = U.map
foldl' = U.foldl'

等等。

建议的方法是概括算法的各个部分,并使用小的松散耦合类型类(如果需要)约束这些部分。
将所有内容收集在一个单一的整体类型类中是一种糟糕的风格。

关于haskell - Haskell 中的 OCaml 仿函数(参数化模块)仿真,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26322406/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com