具有约束返回类型的类型类实例

时间:2016-11-18 08:13:43

标签: haskell overloading type-families associated-types

我正在实现内部产品的概念,这种概念在容器和数字类型上是一般的。该定义指出此操作的返回类型是(非负)实数。 一个选项(如下所示)是为每种数字类型(Float,Double,Complex Float,Complex Double,Complex CFloat,Complex CDouble等)手动编写所有实例。原始类型并不多,但我不喜欢重复。 我认为另一种选择是使用具有约束的参数化实例,例如RealFloat(代表FloatDouble)。

{-# language MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-}
module Test where

import Data.Complex

class Hilbert c e where
  type HT e :: *
  dot :: c e -> c e -> HT e


instance Hilbert [] Double where
  type HT Double = Double
  dot x y = sum $ zipWith (*) x y

instance Hilbert [] (Complex Double) where
  type HT (Complex Double) = Double
  a `dot` b = realPart $ sum $ zipWith (*) (conjugate <$> a) b

问题

为什么下面的实例不起作用(“无法将类型eDouble匹配..预期类型HT e,实际类型e”)?

instance RealFloat e => Hilbert [] e where
  type HT e = Double
  dot x y = sum $ zipWith (*) x y

1 个答案:

答案 0 :(得分:3)

嗯,该特定实例不起作用,因为Double仅产生e,但您希望结果为RealFrac。由于Real 约束为Fractional,但这很容易解决,因为任何 dot x y = realToFrac . sum $ zipWith (*) x y (虽然在数学上是可疑的)都可以转换为{{ 1}}:

instance RealFloat e => Hilbert [] e where

但是,该通用实例会阻止您定义复杂实例:使用Complex覆盖所有类型,即使它们不是真正的实数。您仍然可以将* -> *实例化为重叠的实例,但如果我能帮助它,我宁愿远离那些。

如果应该在public static Stream<String> readFileInChunks(String filePath, int chunkSize) throws IOException { BufferedReader br = new BufferedReader(new FileReader(filePath)); Iterator<String> iter = new Iterator<String>() { String nextChunk = null; @Override public boolean hasNext() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < chunkSize; i++) { try { String nextLine = br.readLine(); if (nextLine == null) break; sb.append(nextLine).append("\n"); } catch (IOException e) { throw new UncheckedIOException(e); } } if (sb.length() == 0) { nextChunk = null; return false; } else { nextChunk = sb.toString(); return true; } } @Override public String next() { if (nextChunk != null || hasNext()) { String chunk = nextChunk; nextChunk = null; return chunk; } else { throw new NoSuchElementException(); } } }; return StreamSupport.stream(Spliterators.spliteratorUnknownSize( iter, Spliterator.ORDERED | Spliterator.NONNULL), false) .onClose(() -> { try { br.close(); } catch (IOException e) { throw new UncheckedIOException(e); } }); } 上定义这样的矢量空间类,那也是值得怀疑的。是的,linear也是这样做的,但IMO参数在这个应用程序中并不适合我们。你看过vector-space package了吗?记住,做严肃的线性代数并不完全完整;我希望用我的linearmap-category package来填补空白。