在尝试调试我的程序中的问题时(使用Gloss将2个具有相同半径的圆圈绘制成不同的大小),我偶然发现了一个奇怪的情况.在我处理对象的文件中,我有以下定义*:
type Coord = (Float,Float)
data Obj = Player { oPos :: Coord, oDims :: Coord }
Run Code Online (Sandbox Code Playgroud)
在导入Objects.hs的主文件中,我有以下定义:
startPlayer :: Obj
startPlayer = Player (0,0) 10
Run Code Online (Sandbox Code Playgroud)
发生这种情况是因为我为玩家添加和更改字段,并且忘记更新Player之后(其尺寸由单个数字确定以表示半径,但我将其更改为a startPlayer来表示(宽度,高度);如果我做的话玩家对象是一个非圆圈).
令人惊奇的是,上面的代码编译并运行,尽管第二个字段是错误的类型.
我首先想到的可能是我打开了不同版本的文件,但对编译程序中的任何文件的任何更改都会反映出来.
接下来我认为可能Coord由于某种原因没有被使用.注释会startPlayer产生编译器错误,甚至更奇怪的是,更改startPlayerin 10会导致适当的响应(更改起始大小startPlayer); 再次,尽管它是错误的类型.为了确保它正确读取数据定义,我在文件中插入了一个拼写错误,它给了我一个错误; 所以我正在查看正确的文件.
我试图粘贴2段以上的到自己的文件,并吐出预期误差的第二场Player中Player是不正确.
什么可能允许这种情况发生?您认为这是Haskell的类型检查器应该阻止的事情.
我应该注意到,我原来的问题的答案,即两个被认为是相同半径的圆被绘制成不同的大小,其中一个半径实际上是负的.
我前段时间编写了一些代码,用于从十六进制编码的字符串文字OverloadedStrings创建ByteStrings,它使用提供的函数进行解码base16-bytestring.这工作得很好,但似乎我并没有像我想的那样理解它.
让我完全困惑的是这个.为什么
{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString.Base16 ()
import qualified Data.ByteString as B
plaintext = "The message" :: B.ByteString
main = print plaintext
Run Code Online (Sandbox Code Playgroud)
编译并运行OK,但如果我删除导入Data.ByteString.Base16然后它无法编译(类似于这个问题):
test.hs:6:13:
No instance for (Data.String.IsString B.ByteString)
arising from the literal `"The message"'
Run Code Online (Sandbox Code Playgroud)
根据Haskell Wiki,这样的导入"仅对导入类型类的实例很有用",但据我所知,base16-bytestring源代码没有定义任何类型类实例,只是encode和decode函数.
导入如何IsString为代码编译提供必要的实例?
我的意思是定义一个类型类的实例,它应用于函数的本地(let或where)范围.更重要的是,我希望在这个实例中的函数是闭包,即能够关闭定义实例的词法范围中的变量(这意味着实例在下次调用它的函数时可能会有不同的工作方式).
我可以为您提供一个简化的用例.假设我有一个基于类型类操作的函数.在这个例子中,我使用平方,它可以在任何类型的实例上运行Num(是的,平方非常简单,可以很容易地重新实现,但它代表的是一些可能更复杂的东西).我需要能够按原样使用现有功能(无需更改或重新实现).
square :: Num a => a -> a
square x = x * x
Run Code Online (Sandbox Code Playgroud)
现在,假设我希望在模运算中使用此操作,即加法,乘法等等.这对于任何固定的模数基都很容易实现,但是我希望有一些通用的东西,我可以为不同的模数基重复使用.我希望能够定义这样的东西:
newtype ModN = ModN Integer deriving (Eq, Show)
-- computes (x * x) mod n
squareModN ::
squareModN x n =
let instance Num ModN where
ModN x * ModN y = ModN ((x * y) `mod` n) -- modular multiplication
_ + _ = undefined -- the rest are unimplemented for simplicity
negate _ = undefined …Run Code Online (Sandbox Code Playgroud) 下面的代码使用不安全的GeneralizedNewtypeDeriving扩展来Data.Set通过插入具有不同Ord实例的不同元素来中断:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Data.Set
import System.Random
class AlaInt i where
fromIntSet :: Set Integer -> Set i
toIntSet :: Set i -> Set Integer
instance AlaInt Integer where
fromIntSet = id
toIntSet = id
newtype I = I Integer deriving (Eq, Show, AlaInt)
instance Ord I where compare (I n1) (I n2) = compare n2 n1 -- sic!
insert' :: Integer -> Set Integer -> Set Integer
insert' n s = …Run Code Online (Sandbox Code Playgroud) 有时候,我遇到了Haskell只匹配实例头的"特性",即
instance (a ~ NewDataTyp b) => C a
Run Code Online (Sandbox Code Playgroud)
现在将匹配任何类型,即C在程序中编写另一个实例声明将是一个错误,即使它不会因上下文而发生冲突a ~ NewDataTyp b.有时,需要付出很多努力才能克服; 我不得不重组数百行代码以避免这种限制.
是否有任何语言扩展或后代语言(Curry?Agda?)的设计具有更高的表现力优先级?这可能会牺牲(a)类型类世界的开放性(b)多项式时间类型检查.
编辑 - 对于那些对这个问题感兴趣的人,这个页面也许是有趣的:http://www.haskell.org/haskellwiki/Future_of_Haskell
有了这个代码
import Control.Monad
import Control.Applicative
import Control.Monad.State
class DefVal a where
defVal :: a
instance (DefVal a) => Alternative (Either a) where
empty = Left defVal
(Left _) <|> x = x
x <|> _ = x
instance (DefVal a) => MonadPlus (Either a) where
mzero = empty
mplus = (<|>)
newtype ErrString = ErrString { toString :: String }
deriving Show
instance DefVal ErrString where
defVal = ErrString "Default Error String"
Run Code Online (Sandbox Code Playgroud)
我收到错误消息:
Duplicate instance declarations:
instance DefVal a => …Run Code Online (Sandbox Code Playgroud) 我有另一个库中定义的数据类型.我想用Control.Lens库生成的镜头挂钩到该数据类型.
我是否需要在我的代码中使用newtype我的类型,或者认为已经定义的数据类型是否安全?
我想要一个名为"double"的泛型函数,其行为与此类似,可以应用于任何类型的def +(x:T):T方法:
double("A")
> "AA"
double(1)
> 2
double(0.2)
> 0.4
Run Code Online (Sandbox Code Playgroud)
所以我写这个函数是这样的:
def double[T](x:T):T = { x+x }
Run Code Online (Sandbox Code Playgroud)
但是当我在REPL中运行它时,scala会对此进行评估:
scala> def double[T](x:T):T = { x+x }
<console>:7: error: type mismatch;
found : T
required: String
def double[T](x:T):T = { x+x }
^
Run Code Online (Sandbox Code Playgroud)
我认为结构类型可能是实现duck typing的一种方法,我尝试过这样的东西,但它也不起作用:
def double[T <: { def +(x:T):T }](x:T):T = { x + x }
def double[T <: { def +[U<:T](x:U):U}](x:T) = { x + x }
Run Code Online (Sandbox Code Playgroud)
有没有人有这个想法?谢谢!
我发现在Haskell中,类似的函数可以像这样写:
double x = x + …Run Code Online (Sandbox Code Playgroud) generics functional-programming scala type-inference duck-typing
让我们考虑以下示例:
data A = A{x::Int} deriving(Show)
instance Func_f (A -> String) where
f _ = "ala"
class Func_f a where
f :: a
main :: IO ()
main = do
let
a = A 5
x = f a
print 5
Run Code Online (Sandbox Code Playgroud)
用.编译 ghc -XFlexibleInstances main.hs
(我试过了-XExtendedDefaultRules,但没有任何进展)
为什么在编译时会出现错误?:
main.hs:25:21:
No instance for (Func_f (A -> t0)) arising from a use of `f'
The type variable `t0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s) …Run Code Online (Sandbox Code Playgroud) 我试图回答这个问题:"给定代数数据类型
data Maybe a = Nothing | Just a
Run Code Online (Sandbox Code Playgroud)
选择正确的实例声明,显示类型构造函数Maybe是一个Monad."(取自这里:"DelftX:FP101x函数式编程简介".
我试图解决的方法是依次编译每个潜在的答案,例如,这个:
instance Monad Maybe where
return x = Just x
Nothing >>= _ = Nothing
(Just x ) >>= f = f x
Run Code Online (Sandbox Code Playgroud)我无法编译它,因为它已在前奏中定义.
HwEx9.hs:16:10: error:
Duplicate instance declarations:
instance Monad Maybe -- Defined at HwEx9.hs:16:10
instance Monad Maybe -- Defined in `GHC.Base'
Run Code Online (Sandbox Code Playgroud)我的问题是:我怎么编译它?
haskell ×9
typeclass ×3
types ×2
duck-typing ×1
duplicates ×1
generics ×1
import ×1
instance ×1
lenses ×1
module ×1
monads ×1
overloading ×1
redefinition ×1
scala ×1
security ×1
type-safety ×1